8

I've seen a couple of people using [<- as a function with Polish notation, for example

x <- matrix(1:4, nrow = 2)
`[<-`(x, 1, 2, 7)

which returns

     [,1] [,2]
[1,]    1    7
[2,]    2    4

I've tried playing around with [<- a little, and it looks like using it this way prints the result of something like x[1,2] <- 7 without actually performing the assignment. But I can't figure out for sure what this function actually does, because the documentation given for ?"[" only mentions it in passing, and I can't search google or SO for "[<-".

And yes, I know that actually using it is probably a horrible idea, I'm just curious for the sake of a better understanding of R.

Empiromancer
  • 3,778
  • 1
  • 22
  • 53
  • 2
    It's more like R converts `x[1,2] <- 7` to be `x <- '[<-'(x, 1, 2, 7)`. – joran Feb 01 '16 at 20:19
  • If you understand the `[` function and the `<-` function, then the `[<-` function makes a lot of sense. Try `[(x,1,2)`. Try `<-(a,1)` – Jacob H Feb 01 '16 at 20:43
  • 2
    I'm not seeing this a duplicate. I _thought_ question is why `[<-` doesn't actually effect a sub-assignment in the symbol/named object `x`. That did not appear to be the question posed in the nominated duplicate. – IRTFM Feb 01 '16 at 20:56
  • `"[<-"` is a function that _returns_ the accordingly modified object. That is what `"[<-"(x, i, value)` seems to do. To see the difference between the explicit `"[<-"` call and how `x[i] <- value` is parsed, perhaps, see `'*tmp*' = "tmp"; x = 1:3; x[2] <- 0; x; get("*tmp*")` VS `'*tmp*' = "tmp"; x = 1:3; "[<-"(x, 2, 0); x; get("*tmp*")` as noted [here](https://cran.r-project.org/doc/manuals/r-release/R-lang.html#Subset-assignment). – alexis_laz Feb 01 '16 at 23:55

2 Answers2

4

This is what you would need to do to get the assignment to stick:

 `<-`(    `[`(   x, 1, 2), 7)  # or x <- `[<-`(   x, 1, 2, 7)
 x
     [,1] [,2]
[1,]    1    7
[2,]    2    4

Essentially what is happening is that [ is creating a pointer into row-col location of x and then <- (which is really a synonym for assign that can also be used in an infix notation) is doing the actual "permanent" assignment. Do not be misled into thinking this is a call-by-reference assignment. I'm reasonably sure there will still be a temporary value of x created.

Your version did make a subassignment (as can be seen by what it returned) but that assignment was only in the local environment of the call to [<- which did not encompass the global environment.

IRTFM
  • 258,963
  • 21
  • 364
  • 487
  • Is `x[1,2]<-7` a call-by-reference then? – fishtank Feb 01 '16 at 23:00
  • Nope. That will create a temporary value as well. Most "regular R" assignments are call by promise which is more like call-by-value than call by reference. The `data.table` package does modifications of its objects in place. The R6 mechanism was set up to provide more direct access to objects and prevent copying overhead. – IRTFM Feb 01 '16 at 23:10
2

Since `[`(x, y) slices an object, and `<-`(x, z) performs assignment, it seems like `[<-`(x,y,z) would perform the assignment x[y] <- y. @42-'s answer is a great explanation of what [<- actually does, and the top answer to `levels<-`( What sorcery is this? provides some insight into why R works this way.

To see what [<- actually does under the hood, you have to go to the C source code, which for [<- can be found at http://svn.r-project.org/R/trunk/src/main/subassign.c (the relevant parts start at around line 1470). You can see that x, the object being "assigned to" is protected so that only the local version is mutated. Instead, we're using VectorAssign, MatrixAssign, ArrayAssign, etc. to perform assignment locally and then returning the result.

Community
  • 1
  • 1
Empiromancer
  • 3,778
  • 1
  • 22
  • 53