[Rd] arguments to .Call(), .External should be read-only?

Radford Neal radford at cs.toronto.edu
Wed Jul 9 21:31:52 CEST 2014


> hi.  if i'm reading correctly, "Writing R Extensions" appears to be
> inconsistent on the question of whether the arguments passed to a
> routine called via .Call() or .External() should considered read-only.

There are two situations to consider.  

1) You want to modify the arguments as a convenience in your
   computation, but in the end you will return information to the
   caller via the value returned from .Call.

2) You want to modify the arguments as a way of returning information
   to the caller.  For instance:

      x <- numeric(100)  # x contains zeros
      .Call("myfunction",x)
      # use new values now present in x

For (1), if you want to modify a argument x, you just need to first
check whether NAMED(x) is non-zero.  If it is, you need to execute
x=duplicate(x) (and probably PROTECT the result) before changing x.
You can return x (the original or the duplicate) as the result of the
.Call if you like, or just use it as an intermediate value in the
computation.

For (2), you need to be sure that the value passed to .Call is
unshared.  (Checking NAMED(x) and duplicating if it is non-zero won't
work, since then the caller doesn't get to see the information put in
the duplicate of x.)  Unfortunately, there is no documentation on when
objects are guaranteed to be unshared.  

The technique of (2) is used sometimes in standard R packages.  For
example, the "arima" function in the "stats" package calls ARIMA_Like
and modifies its arguments as a way of returning information.  It's
presumably also used in many contributed packages.

Since it's probably too much to eliminate all uses of (2), I think
documentation on when an object is guaranteed to be unshared is
needed.  I propose that the following be guaranteed to produce an
unshared object:

  1) The vector creation functions: vector, numeric, integer, logical,
     complex, raw, and character.

  2) The array creation functions: array and matrix.

  3) The rep and rep.int functions, which are sometimes used in place of
     a vector creation function - eg, rep(0,10) rather than numeric(10).

I think it should be assumed that any other function might return an
unshared result (eg, 1-1 might return a shared zero object). Of
course, the results from the above functions might become shared
later, too (if assigned to more than one variable, for instance), but
code like that above for .Call("myfunction",x) would be guaranteed to
work.

   Radford Neal



More information about the R-devel mailing list