[Rd] Problem with new("externalptr")

Herve Pages hpages at fhcrc.org
Wed Jan 30 02:03:18 CET 2008


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 at 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 at 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.
> 
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>



More information about the R-devel mailing list