Marc
Marc

Reputation: 238

Overwrite function temporarily

I want to provide a function called "Sdt" in my package. There are multiple methods of it, but they all lead to Sdt.default(a, b, c, d), which returns a named vector with some calculated stuff for a,b,c and d.

But in some cases the user of my package needs to extend Sdt.default, for example, if he/she wants to try out some other calculations with the four variables.

So I thought: Why not temporarily overwrite the function? So I tried something like this (with Sdt of course, but this is a better toy example):

a <- function() print("FUNCTION A CALLED")
b <- function() print("FUNCTION B CALLED")
c <- function() a()
d <- function(){

  a()
  a <- b
  a()

  c()
}
d()

The outcome looks like

[1] "FUNCTION A CALLED"
[1] "FUNCTION B CALLED"
[1] "FUNCTION A CALLED"

But I want to have

[1] "FUNCTION A CALLED"
[1] "FUNCTION B CALLED"
[1] "FUNCTION B CALLED"

The "<<-" operator would work in this example, but if a() is defined within a package it would throw error messages, ("determined function within a package can't be altered" or something like that)

TL;DR How to override from global environment a function within a package temporarily but completly, so all following and nested calls use the altered function?

Upvotes: 2

Views: 1105

Answers (3)

digEmAll
digEmAll

Reputation: 57210

You could use assign function to put your newly created function into the global environment.
Have a look at this example replacing base sum function :

callSum <- function() sum(1)

main <- function(){

  # here we use the original sum function -> we expect 1
  print(sum(1))

  # let's create a new sum function returning always 100
  # and assign it to the global env. with name "sum"
  # (note that the name of this function object is not important, 
  # but the name used in assign is crucial)
  newSum <- function(v) {return(100)}
  assign("sum", newSum, envir=globalenv())

  # let's call sum(1) -> we expect 100
  print(sum(1))

  # let's call a function that calls sum(1) -> we expect 100
  print(callSum())

  # we don't want to return anything...
  invisible()
}

main()

it prints:

[1] 1
[1] 100
[1] 100

However, this is not really a clean solution.

If you think you need to switch between the package implementation and a custom implementation very often, I suggest to create a wrapper of Std and use it wherever you want to use the Std function. In this way, when you want to stop using the package version, you just have to change the wrapper implementation, e.g. :

StdWrapper <- function(a,b,c,d){
   return(Std(a,b,c,d))
   # return(YourCustomStd(a,b,c,d))

   # as soon as you need to switch to a custom implementation,
   # just comment the first line and uncomment the second and vice-versa 
}

Upvotes: 1

Matthew Plourde
Matthew Plourde

Reputation: 44614

I'm a fan of @DavidArenburg's solution, but if defining default arguments for all of the variables you want to temporarily override isn't an option, this is another way:

d <- function(){
  a()
  a <- b
  a()
  environment(c) <- environment()
  c()
}
d()
# [1] "FUNCTION A CALLED"
# [1] "FUNCTION B CALLED"
# [1] "FUNCTION B CALLED"
c()
# [1] "FUNCTION A CALLED"

Upvotes: 3

David Arenburg
David Arenburg

Reputation: 92282

I wouldn't use neither assign or <<-. I would just modify c() function

a <- function() print("FUNCTION A CALLED")
b <- function() print("FUNCTION B CALLED")
c <- function(x = a) x() 
d <- function(){

  a()
  a <- b
  a()

  c(a)
}
d()

## [1] "FUNCTION A CALLED"
## [1] "FUNCTION B CALLED"
## [1] "FUNCTION B CALLED"

While c() without a parameter will work the same

c()
## [1] "FUNCTION A CALLED"

Upvotes: 3

Related Questions