Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function `[<-` will _replace_ an element, but not append an _element_

I noticed the following when using '[<-'. I am successful at replacing elements but not at appending an element to the vector.

Example:

VarX <- integer()
VarX[1] <- 11
`[<-`(VarX, 2, 22)
VarX
# [1] 11

# Expected the value of VarX to be:  
# [1] 11 22

# Also tried: 
`[<-`(VarX, i=2, value=22)
VarX 
# [1] 11

However, if there is already a value at the index, the value does get replaced.

VarX <- integer()
VarX[1] <- 11
VarX[2] <- 99
VarX
# [1] 11 99
`[<-`(VarX, 2, 22)
VarX
# [1] 11 22

Do I simply have the syntax wrong, or is this as intended? Any further insight into what is going on here would be appreciated.

Please note, there is no concrete objective here other than to better understand the language.

Update regarding @Roland and @Dason 's comments.

It appears that the behavior is tied to how the values of the object are initially assigned. For example, when the value assigned to VarX is 1:2 versus c(1, 2) the behavior of [<-(VarX, 2, 22) gives different results, as shown below:

### changes not saved to VarX

rm(VarX)  # actually ran:     rm(list=ls(all=TRUE))
VarX <- 1:2
VarX
# [1] 1 2

`[<-`(VarX, 2, 22)
# [1]  1 22

VarX
# [1] 1 2

### changes ARE saved to VarX

rm(VarX)  # actually ran:     rm(list=ls(all=TRUE))
VarX <- c(1, 2)
VarX[2] <- 2
VarX
# [1] 1 2

`[<-`(VarX, 2, 22)
# [1]  1 22

VarX
# [1]  1 22



> sessionInfo()
R version 2.15.1 (2012-06-22)
Platform: x86_64-apple-darwin9.8.0/x86_64 (64-bit)

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base  
like image 988
Ricardo Saporta Avatar asked Mar 02 '13 19:03

Ricardo Saporta


1 Answers

The function '[<-' might not replace anything in its first argument. In certain circumstances, it makes a copy of the object and modifies that.

See section 3.4.4 of the language definition:

x[3:5] <- 13:15

The result of this commands is as if the following had been executed

‘*tmp*‘ <- x
x <- "[<-"(‘*tmp*‘, 3:5, value=13:15)
rm(‘*tmp*‘)

This is essentially what will be run if the structure of x must be modified. However, it is clear based on experiments of the OP (and others, including myself) that the "[<-" function can modify elements in-place. Clearly nothing can be done in-place if the entire object is going to be replaced.

In-place substitution:

> x <- 1:2
> class(x)
[1] "integer"
> `[<-`(x, 2, 99L)
[1]  1 99
> x
[1]  1 99

Replacement of the entire object because the type has been changed (in the C function SubAssignTypeFix):

> x <- 1:2
> class(x)
[1] "integer"
> x[2] <- 99
> class(x)
[1] "numeric"

Another situation where the object is replaced, is when there is more than one reference to the object being modified:

x <- 1:2
y <- x
`[<-`(x, 2, 99L)
## [1]  1 99
x
## [1] 1 2

Running R under the debugger shows that the assignment function called indirectly via x[2] <- 99 invokes the C function do_set, whereas this function is not called when the assignment function is called directly by name.

do_set calls a function defineVar which modifies the appropriate environment. In the case of an in-place replacement, the object replaces itself in the environment, which are the exact cases where calling the assignment function by name results in the object being modified (a copy was not taken).

Interesting tidbit (and see here: R object identity)

#### R console:
x <- 1:2
.Internal(inspect(x))
## @26b27a8 13 INTSXP g0c1 [NAM(1)] (len=2, tl=0) 1,2
x[2] <- 99

#### gdb:
Breakpoint 7, do_set (call=0x2773640, op=0x169e668, args=0x2773870, rho=0x16c6b68) at eval.c:1732   
(gdb) p s
## $135 = (SEXP) 0x192bee0
c

#### R console:
.Internal(inspect(x))
## @192bee0 14 REALSXP g0c2 [NAM(1)] (len=2, tl=0) 1,99

To directly answer the original question, when [<- enlarges the vector, a copy is made. From the function EnlargeVector at subassign.c:113:

PROTECT(newx = allocVector(TYPEOF(x), newlen));

/* Copy the elements into place. */
...

This is R 2.15.2, which I built from source without optimization and with debugging info. It is very slow without optimization.

like image 148
Matthew Lundberg Avatar answered Sep 18 '22 14:09

Matthew Lundberg