9

I just discovered that `[<-` may have destructive side-effects or not depending on what arguments one gives it.

Example

x <- 1:5
x
# [1] 1 2 3 4 5
`[<-`(x, 1:5, 1)
# [1] 1 1 1 1 1
x
# [1] 1 2 3 4 5  # ∴ last application of `[<-` was non-destructive
`[<-`(x, 1:5, TRUE)
# [1] 1 1 1 1 1
x
# [1] 1 1 1 1 1  # ∴ the last application of `[<-` had a destructive side-effect

Q: Is there a general way to reliably prevent the destructive behavior, or at least guard against it? (Short, of course, of avoiding `[<-` altogether.)


Notes

  1. I was not able to find the answer to my question in the documentation (?`[<-`); in general, I had a hell of a time finding any official documentation on (?`...<-`)-type "replacement" operators (I don't even know what they're called), and none that addresses head-on the question of side-effects.

  2. Of course, for all I know, even the behavior I've labeled "non-destructive" may still have some other side-effects I'm not aware of.

  3. For the simple example above, the expression as.logical(`[<-`(x, 1:5, 1)) has the same value as as that of `[<-`(x, 1:5, TRUE), and retains the same one-line functionality, but has no (obvious) side-effects. This alternative, however, is not a general solution to this problem.


Update (in response to BrodieG's request)

$ R --quiet --no-save --no-restore
> x <- 1:5
> x
[1] 1 2 3 4 5
> `[<-`(x, 1:5, TRUE)
[1] 1 1 1 1 1
> x
[1] 1 1 1 1 1
> sessionInfo()
R version 3.3.1 (2016-06-21)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Debian GNU/Linux 8 (jessie)

locale:
 [1] LC_CTYPE=en_US.utf8       LC_NUMERIC=C             
 [3] LC_TIME=en_US.utf8        LC_COLLATE=en_US.utf8    
 [5] LC_MONETARY=en_US.utf8    LC_MESSAGES=en_US.utf8   
 [7] LC_PAPER=en_US.utf8       LC_NAME=C                
 [9] LC_ADDRESS=C              LC_TELEPHONE=C           
[11] LC_MEASUREMENT=en_US.utf8 LC_IDENTIFICATION=C      

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     
kjo
  • 33,683
  • 52
  • 148
  • 265
  • 1
    In general, if you do these operations inside a function, any changes to variables will not be propagated to the called environment since everything is pass by value essentially. What are you doing where you think that calling `[<-` directly is necessary? – MrFlick Apr 14 '17 at 13:59
  • 2
    In the cases considered here, you can use `replace` instead, I guess. – Frank Apr 14 '17 at 14:00
  • @MrFlick: I don't know of any situation in which `[<-` is *necessary*. Still, I'd like to know how to use it; this is what motivates the question. – kjo Apr 14 '17 at 14:04
  • 4
    Can you double check that your second example is 'destructive'? – Vlo Apr 14 '17 at 14:05
  • 10
    `"[<-"` avoids copying its argument if it is not referenced elsewhere and/or the replacement is of the same (or <=) `typeof`. Assigning "1" to "1:5" needs to coerce "1:5" to "double", while assigning "1L" or "TRUE" does not. In either case, increasing the number of references of an object (`x2 = x`) will, always, copy "x". `x = 1:5; x2 = x; "[<-"(x, 1:5, 1L); x`. Using, though, the form of `x[i] = val` will save any trouble – alexis_laz Apr 14 '17 at 14:14
  • 2
    @alexis_laz: you should make that an answer. It might help to clarify that `TRUE` doesn't copy because `integer` and `logical` are both represented as `int` in the underlying C code, so no conversion is necessary. You could also use `tracemem(x)` to see when a copy is made. See also: [`levels<-`( What sorcery is this?](http://stackoverflow.com/q/10449366/271616). – Joshua Ulrich Apr 14 '17 at 14:20
  • @Vlo: the interaction I show in the example is copy-pasted verbatim from my screen, exactly as it happened. I don't know what else I can do to convince you that the operation shown is destructive. – kjo Apr 14 '17 at 14:34
  • 1
    Can you show `sessionInfo()`? We're getting mixed results on reproducibility. I can't reproduce this either. – BrodieG Apr 14 '17 at 14:36
  • Okay, I can reproduce this if I run every step, but no if I run only the `"[<-"(x, 1:5, TRUE)` one, so this smells like a bug of some sort. – BrodieG Apr 14 '17 at 14:40
  • @BrodieG: pls see the latest update to my post – kjo Apr 14 '17 at 14:43
  • 1
    I can reproduce this by launching R GUI and running code, but it does not reproduce when running same version of R on Rstudio. (R 3.2.5 MS R open, windows 7). – lmo Apr 14 '17 at 14:49
  • 2
    @lmo probably because Rstudio affects the named status of variables via the environment viewer pane. – BrodieG Apr 14 '17 at 14:51
  • @alexis_laz please post as an answer. You might want to clarify that Rstudio will muddy the waters and the best way to see this is in a normal client. – BrodieG Apr 14 '17 at 14:58
  • 1
    @BrodieG & Alexis: That RStudio side-note can probably be covered by a link here: http://stackoverflow.com/q/15559387/ – Frank Apr 14 '17 at 15:16
  • 1
    I'm closing since I think the link covers it, but would be fine with reopening if there's more to say beyond the scope of the linked question. – Frank Apr 14 '17 at 15:32

0 Answers0