cmbarbu
cmbarbu

Reputation: 4534

R: default value using other argument modified when other argument modified

When defining a default argument y to an R function as being equal to an other argument x. Ex: function(x,y=x). I found that if I change the other argument (x) before using my default argument (y), it also changes the value of y.

I understand it has to do with "delayed copying until modified" but is that really the desired behavior?

Hereafter a full example:

oh_my <- function(x, y=x){
    x <- rev(x)
    y <- rev(y) # the value of y here actually is rev of initial x!
    print(y)
}
oh_my(1:5)

[1] 1 2 3 4 5

An easy solution would be:

ok <- function(x, y=NULL){
    if(is.null(y)){
        y<-x
    }
    x <- rev(x)
    y <- rev(y)
    print(y)
}
ok(1:5)

[1] 5 4 3 2 1

But I actually like the fact that the default is obvious in the first option (including in automatically generated help files).

An other solution would be:

pfiouu <- function(x, y=x){
    y <- rev(y) # the value of y here actually is rev of initial x!
    x <- rev(x)
    print(y)
}

pfiouu(1:5)

[1] 5 4 3 2 1

But it really seems awkward to me that pfiouu and oh_my give different results as the two exchanged lines do not mention explicitly each others variables and yet yield different results!

Am I missing a good practice that would keep the default obvious and avoid that kind of fall-trap?

Upvotes: 1

Views: 546

Answers (1)

cmbarbu
cmbarbu

Reputation: 4534

As suggested by MrFlick, adding force(y) at the start of the function allows to force the evaluation of y and prevents issues like that. It being a desirable behavior in such a high level programming language as R remains open though.

no_surprise<- function(x, y=x){
    force(y)
    x <- rev(x)
    y <- rev(y) 
    print(y)
}
no_surprise(1:5)

[1] 5 4 3 2 1

As expected.

Upvotes: 1

Related Questions