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.
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 >
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. > > ______________________________________________ > R-devel at r-project.org 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 rgentlem at fhcrc.org