Skip to content

Copying objects prior to .Call

5 messages · Taylor Arnold, Simon Urbanek, Douglas Bates +1 more

#
R-devel,

I have noticed that making a copy of an object in R prior to using
.Call on the original object can
cause the C code to alter not only the object passed to it but also
the copy in R. A simple example
is:
NULL
[1] 3
[1] 3

And corresponding simple C code:

"test.c":
#include <R.h>
#include <Rinternals.h>
#include <Rmath.h>

SEXP addOne(SEXP input) {
? REAL(input)[0] = REAL(input)[0] + 1;
? return R_NilValue;
}

I assume that this is simply a result of lazy loading in R, and well
documented. My question is, do
there exist functions to (1) force R to make a copy of an object
(force() does not work), and (2) to check
whether two objects are actually pointing to the same memory address.
For question 1, I have
found specific operations which force a copy of a given datatype, but
would prefer a more general
solution.

Thank you,

Taylor
R version 2.14.1 (2011-12-22)
Platform: x86_64-apple-darwin9.8.0/x86_64 (64-bit)

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

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base

loaded via a namespace (and not attached):
[1] tools_2.14.1


--
Taylor B. Arnold
Department of Statistics
Yale University
24 Hillhouse Avenue
New Haven, CT 06520

e-mail: taylor.arnold at yale.edu
#
On Jan 11, 2012, at 12:08 PM, Taylor Arnold wrote:

            
Please see the docs - .Call does *NOT* have a DUP argument - you are responsible for duplication at all times if you make modifications (e.g. using duplicate()).

Cheers,
Simon
#
On Wed, Jan 11, 2012 at 11:49 AM, Simon Urbanek
<simon.urbanek at r-project.org> wrote:
Except that duplicate will create a new SEXPREC and the original
poster wanted to modify the SEXPREC passed through a pointer in .Call.

Purposely changing the value of arguments to .Call is a bad design,
Taylor.  R is a functional language and this breaks the functional
semantics. It is the sort of thing that you do only when you can't
think of a better approach.  It may, perhaps, be justified if the R
objects you are passing happen to be fields in a reference class (see
?setRefClass) but otherwise it is just opening yourself up to errors.
At the level of C/C++ all R objects passed as arguments to .Call
should be regarded as

const SEXP
#
On 11.01.2012 18:49, Simon Urbanek wrote:
In addition to Simon: it is "lazy evalution" rather than lazy loading in 
this case.

Uwe
#
On Jan 11, 2012, at 1:04 PM, Uwe Ligges wrote:

            
It is actually neither. `x` gets evaluated, but the value is shared with `y` because R has no reason to create a copy of identical information until modified. That's why the .Call() code must create a copy if it wants to touch the value that it received. Note that .Call does *not* get `x` itself - it gets a value obtained from the binding of `x` so the only legal way to modify `x` is to assign a value to it. You can try to be more efficieint and check if a value has references to it and prevent copying if it doesn't (see NAMED), but if it does, you have to copy it.

Cheers,
Simon