From ripley at stats.ox.ac.uk  Thu May 17 14:37:25 2012
From: ripley at stats.ox.ac.uk (Prof Brian Ripley)
Date: Thu, 17 May 2012 13:37:25 +0100
Subject: [Rd] Passing externalptr to .C()
In-Reply-To: <4FB42A8D.1090903@pixar.com>
References: <4FAD828D.1040707@pixar.com> <4FAD93F1.5070803@gmail.com>
	<4FB42A8D.1090903@pixar.com>
Message-ID: <4FB4F105.40504@stats.ox.ac.uk>

On 16/05/2012 23:30, Rick Sayre wrote:
> Thanks very much for the quick reply.
>
> I'd like to avoid static state in the .so, which is why I'm using
> the opaque pointer. It is indeed possible to convert everything to
> .Call(), but the work seems unnecessary given that it used to work
> just fine and I am going out of my way to pass things with correct
> type conversion and semantics. Again, this seems like exactly the
> usage externalptr was designed for, doesn't it?
>
> It seems I can avoid the warnings by putting the externalptr in
> a list:

Actually, 'Writing R Extensions' says:

  .. external pointers should only be used as part of an object with 
normal semantics, for example an attribute or an element of a list.

so that *is* the 'correct semantics' ....

> getDeviceInfo<- function(handle) {
> .C("groovyDevice_getDeviceInfo", PACKAGE="groovyDevice",
> list(handle), # Avoid pedantic warnings via encapsulation
> status = as.integer(0))[-1] # skip handle
> }

> void
> groovyDevice_getDeviceInfo(SEXP *handle, int *status)
> {
> groovyHandle *gh = R_ExternalPtrAddr(*handle);
> *status = GroovyStatus(gh);
> }

> Perhaps this will help others in the same boat in which I find myself.

As has been said here many times recently, .C is an old (some say 
obselete) interface, and pre-dates objects such as external pointers. 
It was chance that this ever worked: it was never designed to.

If you find yourself with C[++] code which uses Rinternals.h it should 
use the .Call/.External interfaces, and there is no guarantee that using 
.C for such things will continue to work (as it is all too easy to break 
R's copying semantics and corrupt loaded R code).

> Cheers
>
> --Rick
>
> On 05/11/2012 03:34 PM, Duncan Murdoch wrote:
>> On 12-05-11 5:20 PM, Rick Sayre wrote:
>>> Greetings.
>>>
>>> 2.15.0 added this behavior
>>> http://developer.r-project.org/blosxom.cgi/R-devel/NEWS/2012/03/29#n2012-03-29
>>>
>>>
>>>
>>> o Passing R objects other than atomic vectors, functions, lists and
>>> environments to .C() is now deprecated and will give a warning.
>>> Most cases (especially NULL) are actually coding errors. NULL
>>> will be disallowed in future.
>>>
>>>
>>> This seems to make sense, except that this case includes externalptrs.
>>>
>>> I have quite a bit of code, designed to interface with various
>>> external hardware devices, which uses this sort of idiom:
>>>
>>> # for example
>>> getDeviceInfo<- function(handle) {
>>> .C("groovyDevice_getDeviceInfo", PACKAGE="groovyDevice",
>>> handle,
>>> status = as.integer(0))[-1] # skip handle
>>> }
>>>
>>> where "handle" was the result of a .Call to a routine which
>>> returned a SEXP which was the result of a R_MakeExternalPtr() call
>>>
>>> The "c" routine looked like:
>>> void
>>> groovyDevice_getDeviceInfo(SEXP handle, int *status)
>>> {
>>> groovyHandle *gh = R_ExternalPtrAddr(handle);
>>> *status = GroovyStatus(gh);
>>> }
>>>
>>> This all used to work fine. As of 2.15.0, I now get this:
>>> Warning message:
>>> In getDeviceInfo() :
>>> passing an object of type 'externalptr' to .C (arg 1) is deprecated
>>>
>>> Passing the same handle to a .Call() does [of course] work fine.
>>>
>>> I thought my usage was exactly as designed. How then should I be
>>> passing an externalptr to a .C() call?
>>
>> I think you shouldn't be doing that. You should be using .Call.
>>
>> If your code can handle external pointer objects (as in the example),
>> this should be an easy transition. I haven't tested this, but I think
>> the conversion to the .Call interface (less error checking) is simply
>>
>> SEXP_getDeviceInfo(SEXP handle, SEXP status)
>> {
>> groovyHandle *gh = R_ExternalPtrAddr(handle);
>> INTEGER(Sstatus)[0] = GroovyStatus(gh);
>> return R_NilValue;
>> }
>>
>>
>> If your code is using the pointer just as an opaque handle, I'd suggest
>> keeping an array of them, and pass an index into that array: then .C
>> will be fine.
>>
>> Duncan Murdoch
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel


-- 
Brian D. Ripley,                  ripley at stats.ox.ac.uk
Professor of Applied Statistics,  http://www.stats.ox.ac.uk/~ripley/
University of Oxford,             Tel:  +44 1865 272861 (self)
1 South Parks Road,                     +44 1865 272866 (PA)
Oxford OX1 3TG, UK                Fax:  +44 1865 272595



[Rd] Passing externalptr to .C()
Prof Brian Ripley