5

By "replacement functions" I mean those mentioned in this thread What are Replacement Functions in R?, ones that look like 'length<-'(x, value). When I was working with such functions I encountered something weird. It seems that a replacement function only works when variables are named according to a certain rule.

Here is my code:

a <- c(1,2,3)

I will try to change the first element of a, using one of the 3 replacement functions below.

'first0<-' <- function(x, value){
  x[1] <- value
  x
}

first0(a) <- 5
a
# returns [1] 5 2 3.

The first one works pretty well... but then when I change the name of arguments in the definition,

'first1<-' <- function(somex, somevalue){
  somex[1] <- somevalue
  somex
}

first1(a) <- 9
# Error in `first1<-`(`*tmp*`, value = 9) : unused argument (value = 9)
a
# returns [1] 5 2 3

It fails to work, though the following code is OK:

a <- 'first1<-'(a, 9)
a
# returns [1] 9 2 3

Some other names work well, too, if they are similar to x and value, it seems:

'first2<-' <- function(x11, value11){
  x11[1] <- value11
  x11
}

first2(a) <- 33
a
# returns [1] 33  2  3

This doesn't make sense to me. Do the names of variables actually matter or did I make some mistakes?

Community
  • 1
  • 1
Qian Qin
  • 53
  • 4

1 Answers1

9

There are two things going on here. First, the only real rule of replacement functions is that the new value will be passed as a parameter named value and it will be the last parameter. That's why when you specify the signature function(somex, somevalue), you get the error unused argument (value = 9) and the assignment doesn't work.

Secondly, things work with the signature function(x11, value11) thanks to partial matching of parameter names in R. Consider this example

f<-function(a, value1234=5) {
    print(value1234)
}    
f(value=5)
# [1] 5

Note that 5 is returned. This behavior is defined under argument matching in the language definition.

Another way to see what's going on is to print the call signature of what's actually being called.

'first0<-' <- function(x, value){
    print(sys.call())
    x[1] <- value
    x
}
a <- c(1,2,3)
first0(a) <- 5
# `first0<-`(`*tmp*`, value = 5)

So the first parameter is actually passed as an unnamed positional parameter, and the new value is passed as the named parameter value=. This is the only parameter name that matters.

MrFlick
  • 195,160
  • 17
  • 277
  • 295
  • Thank you for the helpful answer! So one of the parameters does have a fixed name (I still feel this is strange!). How about `a <- 'first1<-'(a, 9)`? Isn't it the same thing as `first1(a) <- 9`? Why does the former work even when I use `first1 <- function(somex, somevalue)` while the latter does not? – Qian Qin Sep 02 '14 at 00:37
  • 3
    When you call `a <- 'first1<-'(a, 9)`, that's resolved using positional parameters. Nothing is named. But when R turns `first1(a) <- 9` into a function call, it turns it into `a <- 'first1<-'(a, value=9)`. When you use a parameter name, you are no longer using positional parameters. – MrFlick Sep 02 '14 at 01:01