Every once in a while I come across the notion that R has copy-on-modify semantics, for example in Hadley's devtools wiki.
Most R objects have copy-on-modify semantics, so modifying a function
argument does not change the original value
I can trace this term back to the R-Help mailing list. For example, Peter Dalgaard wrote in July 2003:
R is a functional language, with lazy evaluation and weak dynamic
typing (a variable can change type at will: a <- 1 ; a <- "a" is
allowed). Semantically, everything is copy-on-modify although some
optimization tricks are used in the implementation to avoid the worst
inefficiencies.
Similarly, Peter Dalgaard wrote in Jan 2004:
R has copy-on-modify semantics (in principle and sometimes in
practice) so once part of an object changes, you may have to look in
new places for anything that contained it, including possibly the
object itself.
Even further back, in Feb 2000 Ross Ihaka said:
We put quite a bit of work into making this happen. I would describe
the semantics as "copy on modify (if necessary)". Copying is done
only when objects are modified. The (if necessary) part means that if
we can prove that the modification cannot change any non-local
variables then we just go ahead and modify without copying.
It's not in the manual
No matter how hard I've searched, I can't find a reference to "copy-on-modify" in the R manuals, neither in R Language Definition nor in R Internals
Question
My question has two parts:
- Where is this formally documented?
- How does copy-on-modify work?
For example, is it proper to talk about "pass-by-reference", since a promise gets passed to the function?
Best Answer
Call-by-value
The R Language Definition says this (in section 4.3.3 Argument Evaluation)
Whilst this does not describe the mechanism by which copy-on-modify works, it does mention that changing an object passed to a function doesn't affect the original in the calling frame.
Additional information, particularly on the copy-on-modify aspect are given in the description of
SEXP
s in the R Internals manual, section 1.1.2 Rest of Header. Specifically it states [Emphasis added]Whilst this doesn't describe the situation whereby objects are passed to functions as arguments, we might deduce that the same process operates, especially given the information from the R Language definition quoted earlier.
Promises in function evaluation
I don't think it is quite correct to say that a promise is passed to the function. The arguments are passed to the function and the actual expressions used are stored as promises (plus a pointer to the calling environment). Only when an argument gets evaluated is the expression stored in the promise retrieved and evaluated within the environment indicated by the pointer, a process known as forcing.
As such, I don't believe it is correct to talk about pass-by-reference in this regard. R has call-by-value semantics but tries to avoid copying unless a value passed to an argument is evaluated and modified.
The NAMED mechanism is an optimisation (as noted by @hadley in the comments) which allows R to track whether a copy needs to be made upon modification. There are some subtleties involved with exactly how the NAMED mechanism operates, as discussed by Peter Dalgaard (in the R Devel thread @mnel cites in their comment to the question)