[Rd] Extra copies of objects in environments when using $ operator?

Winston Chang winstonchang1 at gmail.com
Fri Aug 5 18:14:40 CEST 2016


My understanding is that R will not make copies of lists if there is
only one reference to the object. However, I've encountered a case
where R does make copies, even though (I think) there should be only
one reference to the object. I hope that someone could shed some light
on why this is happening.

I'll start with a simple example. Below, x is a list with one element,
and changing that element doesn't result in a copy. (We know this
because nothing is printed when we do the assignment after the
tracemem call.) This is as expected.
  x <- list(1)
  tracemem(x)
  # [1] "<0x1149e08f8>"
  x[[1]] <- 2
  # (No output)

Similarly, modifying a list contained in a list doesn't result in a copy:
  e <- list(x = list(1))
  tracemem(e$x)
  # [1] "<0x11b3a4b38>"
  e$x[[1]] <- 2
  # (No output)

However, modifying a list contained in an environment *does* result in
a copy -- tracemem prints out some info when we do the assignment:
  e <- new.env(parent = emptyenv())
  e$x <- list(1)
  tracemem(e$x)
  # [1] "<0x1148c1708>"
  e$x[[1]] <- 2
  # tracemem[0x1148c1708 -> 0x11b2fc1b8]:


This is surprising to me. Why is a copy made in this case? It also
results in slower performance for these situations.

The most that I've been able to figure out is that it probably has
something to do with how the $ operator works with environments (but
not with lists). If you do the same operations without the $ operator,
by evaluating code in environment e, then no copy is made:

  e <- new.env(parent = globalenv())
  eval(quote({
    x <- list(1)
    tracemem(x)
    x[[1]] <- 2
  }), envir = e)
  # (No output)


I'd appreciate it if someone could shed light on this. And if it's a
bug, that would be good to know too.

-Winston



More information about the R-devel mailing list