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.
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With