Problem with new("externalptr")

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Problem with new("externalptr")

Hervé Pagès
Hi,

It seems that new("externalptr") is always returning the same instance, and
not a new one as one would expect from a call to new(). Of course this is hard
to observe:

  > new("externalptr")
  <pointer: (nil)>
  > new("externalptr")
  <pointer: (nil)>

since not a lot of details are displayed.

For example, it's easy to see that 2 consecutive calls to new("environment")
create different instances:

  > new("environment")
  <environment: 0xc89d10>
  > new("environment")
  <environment: 0xc51248>

But for new("externalptr"), I had to use the following C routine:

  SEXP sexp_address(SEXP s)
  {
        SEXP ans;
        char buf[40];

        snprintf(buf, sizeof(buf), "%p", s);
        PROTECT(ans = NEW_CHARACTER(1));
        SET_STRING_ELT(ans, 0, mkChar(buf));
        UNPROTECT(1);
        return ans;
  }

Then I get:

  > .Call("sexp_address", new("externalptr"))
  [1] "0xde2ce0"
  > .Call("sexp_address", new("externalptr"))
  [1] "0xde2ce0"

Isn't that wrong?

I worked around this problem by writing the following C routine:

  SEXP xp_new()
  {
        return R_MakeExternalPtr(NULL, R_NilValue, R_NilValue);
  }

so I can create new "externalptr" instances from R with:

  .Call("xp_new")

I understand that there is not much you can do from R with an "externalptr"
instance and that you will have to manipulate them at the C level anyway.
But since new("externalptr") exists and seems to work, wouldn't that be
better if it was really creating a new instance at each call?

Thanks!
H.

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Problem with new("externalptr")

Hervé Pagès
Hi again,

Here is an example of an annoyance that I think is directly related to the
problem with new("externalptr"). When you try to extend the "externalptr" class:

  > setClass("ExternalInteger", contains="externalptr")
  [1] "ExternalInteger"

then every call to new("ExternalInteger") will return the same instance too.

I've tried to define an "initialize" method for "ExternalInteger" objects, but,
whatever I do, I end up with the same "ExternalInteger" instance. So in the end
I had to define the "ExternalInteger" class this way:

  > setClass("ExternalInteger", representation(xp="externalptr"))

even if I'd really like to be able to use the "is a" semantic and not the "has a"
semantic.

Then I use my xp_new() C routine (see previous post) for initializing the xp slot:

  setMethod("initialize", "ExternalInteger",
    function(.Object, ...)
    {
        .Object@xp <- .Call("xp_new")
        ...
        .Object
    }
  )

Then everytime I need to pass an "ExternalInteger" instance x to a C routine,
I need to perform one extra step to reach the externalptr (need to pass x@xp to
the routine instead of x itself).

So unfortunately, things are quite ugly and more painful than necessary.

Thanks,
H.


Herve Pages wrote:

> Hi,
>
> It seems that new("externalptr") is always returning the same instance, and
> not a new one as one would expect from a call to new(). Of course this is hard
> to observe:
>
>   > new("externalptr")
>   <pointer: (nil)>
>   > new("externalptr")
>   <pointer: (nil)>
>
> since not a lot of details are displayed.
>
> For example, it's easy to see that 2 consecutive calls to new("environment")
> create different instances:
>
>   > new("environment")
>   <environment: 0xc89d10>
>   > new("environment")
>   <environment: 0xc51248>
>
> But for new("externalptr"), I had to use the following C routine:
>
>   SEXP sexp_address(SEXP s)
>   {
>         SEXP ans;
>         char buf[40];
>
>         snprintf(buf, sizeof(buf), "%p", s);
>         PROTECT(ans = NEW_CHARACTER(1));
>         SET_STRING_ELT(ans, 0, mkChar(buf));
>         UNPROTECT(1);
>         return ans;
>   }
>
> Then I get:
>
>   > .Call("sexp_address", new("externalptr"))
>   [1] "0xde2ce0"
>   > .Call("sexp_address", new("externalptr"))
>   [1] "0xde2ce0"
>
> Isn't that wrong?
>
> I worked around this problem by writing the following C routine:
>
>   SEXP xp_new()
>   {
>         return R_MakeExternalPtr(NULL, R_NilValue, R_NilValue);
>   }
>
> so I can create new "externalptr" instances from R with:
>
>   .Call("xp_new")
>
> I understand that there is not much you can do from R with an "externalptr"
> instance and that you will have to manipulate them at the C level anyway.
> But since new("externalptr") exists and seems to work, wouldn't that be
> better if it was really creating a new instance at each call?
>
> Thanks!
> H.
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Problem with new("externalptr")

Luke Tierney
On Tue, 29 Jan 2008, Herve Pages wrote:

> Hi again,
>
> Here is an example of an annoyance that I think is directly related to the
> problem with new("externalptr"). When you try to extend the "externalptr" class:

You don't wnat to do that for the same reason you don't want to do it
with environments: Like environment external pointers are reference
objects, so things like unclass and other attribute changes end up
being destructive.  Create the thing you want as a list wrapper around
the external pointer.  You'll be a lot happier with the result in the
long run.

luke


>
>  > setClass("ExternalInteger", contains="externalptr")
>  [1] "ExternalInteger"
>
> then every call to new("ExternalInteger") will return the same instance too.
>
> I've tried to define an "initialize" method for "ExternalInteger" objects, but,
> whatever I do, I end up with the same "ExternalInteger" instance. So in the end
> I had to define the "ExternalInteger" class this way:
>
>  > setClass("ExternalInteger", representation(xp="externalptr"))
>
> even if I'd really like to be able to use the "is a" semantic and not the "has a"
> semantic.
>
> Then I use my xp_new() C routine (see previous post) for initializing the xp slot:
>
>  setMethod("initialize", "ExternalInteger",
>    function(.Object, ...)
>    {
>        .Object@xp <- .Call("xp_new")
>        ...
>        .Object
>    }
>  )
>
> Then everytime I need to pass an "ExternalInteger" instance x to a C routine,
> I need to perform one extra step to reach the externalptr (need to pass x@xp to
> the routine instead of x itself).
>
> So unfortunately, things are quite ugly and more painful than necessary.
>
> Thanks,
> H.
>
>
> Herve Pages wrote:
>> Hi,
>>
>> It seems that new("externalptr") is always returning the same instance, and
>> not a new one as one would expect from a call to new(). Of course this is hard
>> to observe:
>>
>>  > new("externalptr")
>>   <pointer: (nil)>
>>  > new("externalptr")
>>   <pointer: (nil)>
>>
>> since not a lot of details are displayed.
>>
>> For example, it's easy to see that 2 consecutive calls to new("environment")
>> create different instances:
>>
>>  > new("environment")
>>   <environment: 0xc89d10>
>>  > new("environment")
>>   <environment: 0xc51248>
>>
>> But for new("externalptr"), I had to use the following C routine:
>>
>>   SEXP sexp_address(SEXP s)
>>   {
>>         SEXP ans;
>>         char buf[40];
>>
>>         snprintf(buf, sizeof(buf), "%p", s);
>>         PROTECT(ans = NEW_CHARACTER(1));
>>         SET_STRING_ELT(ans, 0, mkChar(buf));
>>         UNPROTECT(1);
>>         return ans;
>>   }
>>
>> Then I get:
>>
>>  > .Call("sexp_address", new("externalptr"))
>>   [1] "0xde2ce0"
>>  > .Call("sexp_address", new("externalptr"))
>>   [1] "0xde2ce0"
>>
>> Isn't that wrong?
>>
>> I worked around this problem by writing the following C routine:
>>
>>   SEXP xp_new()
>>   {
>>         return R_MakeExternalPtr(NULL, R_NilValue, R_NilValue);
>>   }
>>
>> so I can create new "externalptr" instances from R with:
>>
>>   .Call("xp_new")
>>
>> I understand that there is not much you can do from R with an "externalptr"
>> instance and that you will have to manipulate them at the C level anyway.
>> But since new("externalptr") exists and seems to work, wouldn't that be
>> better if it was really creating a new instance at each call?
>>
>> Thanks!
>> H.
>>
>> ______________________________________________
>> [hidden email] mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>

--
Luke Tierney
Chair, Statistics and Actuarial Science
Ralph E. Wareham Professor of Mathematical Sciences
University of Iowa                  Phone:             319-335-3386
Department of Statistics and        Fax:               319-335-3017
    Actuarial Science
241 Schaeffer Hall                  email:      [hidden email]
Iowa City, IA 52242                 WWW:  http://www.stat.uiowa.edu

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Problem with new("externalptr")

Hervé Pagès
Luke Tierney wrote:

> On Tue, 29 Jan 2008, Herve Pages wrote:
>
>> Hi again,
>>
>> Here is an example of an annoyance that I think is directly related to
>> the
>> problem with new("externalptr"). When you try to extend the
>> "externalptr" class:
>
> You don't wnat to do that for the same reason you don't want to do it
> with environments: Like environment external pointers are reference
> objects, so things like unclass and other attribute changes end up
> being destructive.  Create the thing you want as a list wrapper around
> the external pointer.  You'll be a lot happier with the result in the
> long run.

Thanks Luke!

As you've probably seen further below in my post, wrapping instead of extending
is indeed what I'm doing. And I'm explaining why I don't really have the choice
right now.
I understand why, generally speaking, you would recommend wrapping instead of
extending, but, given the context where I'm making use of those external pointers
(the "ExternalInteger" class itself is not exported, only used internally as slots
of higher level objects, never accessed directly, etc..., etc...), I don't think
extending would actually be a problem.

Unfortunately, because of the problem with new("externalptr"), I can't even
experiment the "extending" approach, test it, compare it with the "wrapping"
approach, etc... and make my own opinion.
And even if I stick with the "wrapping" approach, it would help to have
new("externalptr") doing what I think is the right thing to do.

Cheers,
H.


>
> luke
>
>
>>
>>  > setClass("ExternalInteger", contains="externalptr")
>>  [1] "ExternalInteger"
>>
>> then every call to new("ExternalInteger") will return the same
>> instance too.
>>
>> I've tried to define an "initialize" method for "ExternalInteger"
>> objects, but,
>> whatever I do, I end up with the same "ExternalInteger" instance. So
>> in the end
>> I had to define the "ExternalInteger" class this way:
>>
>>  > setClass("ExternalInteger", representation(xp="externalptr"))
>>
>> even if I'd really like to be able to use the "is a" semantic and not
>> the "has a"
>> semantic.
>>
>> Then I use my xp_new() C routine (see previous post) for initializing
>> the xp slot:
>>
>>  setMethod("initialize", "ExternalInteger",
>>    function(.Object, ...)
>>    {
>>        .Object@xp <- .Call("xp_new")
>>        ...
>>        .Object
>>    }
>>  )
>>
>> Then everytime I need to pass an "ExternalInteger" instance x to a C
>> routine,
>> I need to perform one extra step to reach the externalptr (need to
>> pass x@xp to
>> the routine instead of x itself).
>>
>> So unfortunately, things are quite ugly and more painful than necessary.
>>
>> Thanks,
>> H.
>>
>>
>> Herve Pages wrote:
>>> Hi,
>>>
>>> It seems that new("externalptr") is always returning the same
>>> instance, and
>>> not a new one as one would expect from a call to new(). Of course
>>> this is hard
>>> to observe:
>>>
>>>  > new("externalptr")
>>>   <pointer: (nil)>
>>>  > new("externalptr")
>>>   <pointer: (nil)>
>>>
>>> since not a lot of details are displayed.
>>>
>>> For example, it's easy to see that 2 consecutive calls to
>>> new("environment")
>>> create different instances:
>>>
>>>  > new("environment")
>>>   <environment: 0xc89d10>
>>>  > new("environment")
>>>   <environment: 0xc51248>
>>>
>>> But for new("externalptr"), I had to use the following C routine:
>>>
>>>   SEXP sexp_address(SEXP s)
>>>   {
>>>         SEXP ans;
>>>         char buf[40];
>>>
>>>         snprintf(buf, sizeof(buf), "%p", s);
>>>         PROTECT(ans = NEW_CHARACTER(1));
>>>         SET_STRING_ELT(ans, 0, mkChar(buf));
>>>         UNPROTECT(1);
>>>         return ans;
>>>   }
>>>
>>> Then I get:
>>>
>>>  > .Call("sexp_address", new("externalptr"))
>>>   [1] "0xde2ce0"
>>>  > .Call("sexp_address", new("externalptr"))
>>>   [1] "0xde2ce0"
>>>
>>> Isn't that wrong?
>>>
>>> I worked around this problem by writing the following C routine:
>>>
>>>   SEXP xp_new()
>>>   {
>>>         return R_MakeExternalPtr(NULL, R_NilValue, R_NilValue);
>>>   }
>>>
>>> so I can create new "externalptr" instances from R with:
>>>
>>>   .Call("xp_new")
>>>
>>> I understand that there is not much you can do from R with an
>>> "externalptr"
>>> instance and that you will have to manipulate them at the C level
>>> anyway.
>>> But since new("externalptr") exists and seems to work, wouldn't that be
>>> better if it was really creating a new instance at each call?
>>>
>>> Thanks!
>>> H.
>>>
>>> ______________________________________________
>>> [hidden email] mailing list
>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>>
>>
>> ______________________________________________
>> [hidden email] mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>
>

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Problem with new("externalptr")

Robert Gentleman
In reply to this post by Hervé Pagès
Hi,

Herve Pages wrote:

> Hi,
>
> It seems that new("externalptr") is always returning the same instance, and
> not a new one as one would expect from a call to new(). Of course this is hard
> to observe:
>
>   > new("externalptr")
>   <pointer: (nil)>
>   > new("externalptr")
>   <pointer: (nil)>
>
> since not a lot of details are displayed.
>
> For example, it's easy to see that 2 consecutive calls to new("environment")
> create different instances:
>
>   > new("environment")
>   <environment: 0xc89d10>
>   > new("environment")
>   <environment: 0xc51248>

   getMethod("initialize", "environment")
and

   getMethod("initialize", "externalptr")

  will give some hints about the difference.

>
> But for new("externalptr"), I had to use the following C routine:
>
>   SEXP sexp_address(SEXP s)
>   {
>         SEXP ans;
>         char buf[40];
>
>         snprintf(buf, sizeof(buf), "%p", s);
>         PROTECT(ans = NEW_CHARACTER(1));
>         SET_STRING_ELT(ans, 0, mkChar(buf));
>         UNPROTECT(1);
>         return ans;
>   }
>
> Then I get:
>
>   > .Call("sexp_address", new("externalptr"))
>   [1] "0xde2ce0"
>   > .Call("sexp_address", new("externalptr"))
>   [1] "0xde2ce0"
>
> Isn't that wrong?

   Not what you want, but not wrong. In the absence of an initialize
method all calls to "new" are guaranteed to return the prototype; so I
think it behaves as documented.

   new("environment") would also always return the same environment,
were it not for the initialize method.  So you might want to contribute
an initialize method for externalptr, but as you said, they are not
useful at the R level so I don't know just what problem is being solved.

   This piece of code might be useful in such a construction
.Call("R_externalptr_prototype_object", PACKAGE = "methods")

  which does what you would like.

  best wishes
    Robert

>
> I worked around this problem by writing the following C routine:
>
>   SEXP xp_new()
>   {
>         return R_MakeExternalPtr(NULL, R_NilValue, R_NilValue);
>   }
>
> so I can create new "externalptr" instances from R with:
>
>   .Call("xp_new")
>
> I understand that there is not much you can do from R with an "externalptr"
> instance and that you will have to manipulate them at the C level anyway.
> But since new("externalptr") exists and seems to work, wouldn't that be
> better if it was really creating a new instance at each call?
>
> Thanks!
> H.
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>

--
Robert Gentleman, PhD
Program in Computational Biology
Division of Public Health Sciences
Fred Hutchinson Cancer Research Center
1100 Fairview Ave. N, M2-B876
PO Box 19024
Seattle, Washington 98109-1024
206-667-7700
[hidden email]

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel