From whorfin at pixar.com  Thu May 17 00:30:37 2012
From: whorfin at pixar.com (Rick Sayre)
Date: Wed, 16 May 2012 15:30:37 -0700
Subject: [Rd] Passing externalptr to .C()
In-Reply-To: <4FAD93F1.5070803@gmail.com>
References: <4FAD828D.1040707@pixar.com> <4FAD93F1.5070803@gmail.com>
Message-ID: <4FB42A8D.1090903@pixar.com>

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:

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.

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



[Rd] Passing externalptr to .C()
Rick Sayre