Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unexpected behaviour with argument defaults

Tags:

r

I just ran into something odd, which hopefully someone here can shed some light on. Basically, when a function has an argument whose default value is the argument's name, strange things happen (well, strange to me anyway).

For example:

y <- 5

f <- function(x=y) x^2

f2 <- function(y=y) y^2

I would consider f and f2 to be equivalent; although they use different variable names internally, they should both pick up the y object in the global environment to use as the default. However:

> f()
[1] 25

> f2()
Error in y^2 : 'y' is missing

Not sure why that is happening.

Just to make things even more interesting:

f3 <- function(y=y) y$foo

> f3()
Error in f3() : 
  promise already under evaluation: recursive default argument reference or earlier problems?

I expected f3 to throw an error, but not that one!

This was tested on R 2.11.1, 2.12.2, and 2.14, on 32-bit Windows XP SP3. Only the standard packages loaded.

like image 499
Hong Ooi Avatar asked Dec 08 '11 02:12

Hong Ooi


1 Answers

Default arguments are evaluated inside the scope of the function. Your f2 is similar (almost equivalent) to the following code:

f2 = function(y) {
    if (missing(y)) y = y
    y^2
}

This makes the scoping clearer and explains why your code doesn’t work.

Note that this is only true for default arguments; arguments that are explicitly passed are (of course) evaluated in the scope of the caller.

Lazy evaluation, on the other hand, has nothing to do with this: all arguments are lazily evaluated, but calling f2(y) works without complaint. To show that lazy evaluation always happens, consider this:

f3 = function (x) {
    message("x has not been evaluated yet")
    x
}

f3(message("NOW x has been evaluated")

This will print, in this order:

x has not been evaluated yet
NOW x has been evaluated
like image 124
Konrad Rudolph Avatar answered Nov 02 '22 23:11

Konrad Rudolph