2

Is it possible to wrap an R function to amend its functionality?

Here's a toy example to explain what I mean. Consider this function sum2:

 sum2 <- function (x) if (length(x) == 1) { cat(x); sum(x) } else sum(x)

It does what sum does, with a tiny modification. Suppose I'd like to redefine sum itself to do what sum2 does here. How can I do this in a general way, without knowing anything about the internals of the function I'm wrapping?

I would like to do this to temporarily "fix" a package function without having to modify and -reinstall the package. I would like to check for its inputs and return a special value in case the input satisfies some condition.

(For those who are deeply familiar with Mathematica, I'm looking for something similar to the Gayley-Villegas trick.)

Community
  • 1
  • 1
Szabolcs
  • 24,728
  • 9
  • 85
  • 174

2 Answers2

5

You need to be careful with this. All packages now have Namespaces and will call the other functions within the same namespace. Your approach will probably work when you call functions from main command prompt. But functions in the package will call the original function, not your modification.

Look at the help for assignInNamespace and related functions for ways to make the changes within the Namespace. The trace function is another way to modify a function in place, adding some additional code to the existing function.

Greg Snow
  • 48,497
  • 6
  • 83
  • 110
  • It is good that you point out this. Can you show how to do the same thing (this toy example) using `trace`? Actually I wanted to modify the return value of a function is an input value satisfies given conditions. – Szabolcs May 11 '13 at 14:15
  • If you use `trace` with `edit=TRUE` then you can edit the body of the function however you want. Put in the if statement on the input statement, then modify the output. – Greg Snow May 11 '13 at 15:06
  • This is very nice to know. But this editing has to be manual, and I'm aiming for a programmatic modification of a function. Imagine this: a package function is broken (or I strongly suspect that it is). Other packages use this function. I want to fix the package function temporarily, after the package has been loaded, without modifying the package source. I.e. `library(somePackage)` then run a script that automatically fixes a function from `somePackage`, but only if I wish to (i.e. not modify the package source permanently). – Szabolcs May 12 '13 at 22:26
  • @Szabolcs, you can also use `trace` with the `at` argument to insert an expression at a given location of the function. See the details in `?trace`. Whether this will be simpler or more complicated than using `assignInNamespace` is hard to judge. – Greg Snow May 13 '13 at 15:42
-1

Something along these lines has worked:

sum2 <- sum
sum <- function (x) if (length(x) == 1) { cat(x); sum2(x) } else sum2(x)

What I did not realize is that I could just store the original definition of sum in sum2 so I can call it from the redefined sum.

As Matthew notes this won't override sum when it is called as base::sum.

Szabolcs
  • 24,728
  • 9
  • 85
  • 174
  • 2
    That works for some uses. But another package may call `sum` as `base::sum` and won't see your definition. – Matthew Lundberg May 11 '13 at 03:25
  • 1
    To whoever downvoted: Instead of downvoting a solution that does work in practice for many cases (even if not all), how about posting a better one? There's currently no other answer that would have solved the actual problem I was having. This one did, so I shared it instead of leaving the question to languish. – Szabolcs May 13 '13 at 13:26