Re: [Rd] external pointers
I don't entirely follow Ross's outline below (?how does the R object 'opaque' get to feature in the call to 'docompute'?), but I have written large amounts of R-linked Delphi code with persistent Delphi objects, using only the '.C' interface and no external pointers. You might find this useful if you want to avoid the complexities of '.Call' and SEXPs etc. NB the C/Delphi distincition is not important here. (i)The first '.C' call uses Delphi code to allocate (using Delphi's own memory manager) and set up a persistent object that R doesn't know about. The Delphi code then returns an "opaque" integer-valued handle to R, which is the address of the object in the Delphi DLL's world. (ii) For subsequent '.C' calls to Delphi from R, I pass in the handle, which I then typecast to an object pointer inside Delphi. Hence I can "find" the persistent object. This way there can be several persistent objects simultaneously-- I'm not limited to global variables in the Delphi DLL. (iii) There is a final cleanup '.C' call which deallocates the persistent object. I sometimes also automate the destruction in the cleanup code of the DLL, just in case the R user forgets to cleanup. I have also gotten this to work after replacing Delphi's memory manager with R's own-- there was no difference (but apparently no point either, from what I've been told). There are some further notes inside a PDF on Duncan Murdoch's page: http://www.stats.uwo.ca/faculty/murdoch/software/compilingDLLs/pascal.ht ml The notes are very Delphi-flavoured (and refer to S not R, since I've used the method both with S-plus and R) but the point should-- or might-- be clear. HTH Mark Mark Bravington CSIRO Mathematical & Information Sciences Marine Laboratory Castray Esplanade Hobart 7001 TAS ph (+61) 3 6232 5118 fax (+61) 3 6232 5012 mob (+61) 438 315 623 > -Original Message- > From: [EMAIL PROTECTED] > [mailto:[EMAIL PROTECTED] On Behalf Of Byron Ellis > Sent: Saturday, 10 December 2005 11:24 AM > To: Ross Boylan > Cc: R Development List > Subject: Re: [Rd] external pointers > > use a C finalizer... > > void MyObject_finalize(SEXP opaque) { > MyObject *obj = (MyObject*)R_ExternalPtrAddr(opaque); > if(NULL != obj) delete obj; > } > > and in your setup code... > > PROTECT(p = R_MakeExternalPtr(...)); > R_RegisterCFinalizer(p,MyObject_finalize); > > > > > > > On Dec 9, 2005, at 3:04 PM, Ross Boylan wrote: > > > I have some C data I want to pass back to R opaquely, and > then back to > > C. I understand external pointers are the way to do so. > > > > I'm trying to find how they interact with garbage collection and > > object lifetime, and what I need to do so that the memory > lives until > > the calling R process ends. > > > > Could anyone give me some pointers? I haven't found much > > documentation. > > An earlier message suggested looking at simpleref.nw, but I > can't find > > that file. > > > > So the overall pattern, from R, would look like opaque <- > setup(arg1, > > arg2, ) # setup calls a C fn docompute(arg1, argb, opaque) # > > many times. docompute also calls C # and then when I return > opaque and > > the memory it's wrapping get #cleaned up. If necessary I could do > > teardown(opaque) # at the end > > > > "C" is actually C++ via a C interface, if that matters. In > > particular, the memory allocated will likely be from the > C++ run-time, > > and needs C++ destructors. > > > > -- > > Ross Boylan wk: (415) 514-8146 > > 185 Berry St #5700 > [EMAIL PROTECTED] > > Dept of Epidemiology and Biostatistics fax: (415) 514-8150 > > University of California, San Francisco > > San Francisco, CA 94107-1739 hm: (415) 550-1062 > > > > __ > > R-devel@r-project.org mailing list > > https://stat.ethz.ch/mailman/listinfo/r-devel > > --- > Byron Ellis ([EMAIL PROTECTED]) > "Oook" -- The Librarian > > __ > R-devel@r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel > > __ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel
Re: [Rd] external pointers
Mark, On Dec 12, 2005, at 7:48 AM, <[EMAIL PROTECTED]> wrote: > (i)The first '.C' call uses Delphi code to allocate (using Delphi's > own memory manager) and set up a persistent object that R doesn't > know about. The Delphi code then returns an "opaque" integer-valued > handle to R, which is the address of the object in the Delphi DLL's > world. That's a bad idea for a couple of reasons, the main being that integer is not guaranteed to be able to hold a pointer - it won't work on any 64-bit platform. Second drawback is that you have no way to link the life of the R object to your Delphi object, because there is no way gc will tell you that the object is gone. This will lead to memory leaks. [Been there, done that ;)] Both issues are solved by the external pointers. > (iii) There is a final cleanup '.C' call which deallocates the > persistent object. I sometimes also automate the destruction in the > cleanup code of the DLL, just in case the R user forgets to cleanup. How do you make sure the no one uses the now invalid integer value? There can be many copies of your proxy object around and they all point to nirvana ... Cheers, Simon __ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel
Re: [Rd] external pointers
Hi Simon Thanks for that... see below for my feeble counterblasts! (And two questions.) > Mark, > > On Dec 12, 2005, at 7:48 AM, <[EMAIL PROTECTED]> wrote: > > > (i)The first '.C' call uses Delphi code to allocate (using Delphi's > > own memory manager) and set up a persistent object that R > doesn't know > > about. The Delphi code then returns an "opaque" > integer-valued handle > > to R, which is the address of the object in the Delphi DLL's world. > > That's a bad idea for a couple of reasons, the main being > that integer is not guaranteed to be able to hold a pointer - > it won't work on any 64-bit platform. Very true, though 64 bit systems are not a big worry for Delphi 6.0 writers... ;) I did once speculate about hacking around this sort of thing by encoding into character strings instead of integers, uggg. > Second drawback is that > you have no way to link the life of the R object to your > Delphi object, because there is no way gc will tell you that > the object is gone. This will lead to memory leaks. [Been > there, done that ;)] Both issues are solved by the external pointers. > > > (iii) There is a final cleanup '.C' call which deallocates the > > persistent object. I sometimes also automate the destruction in the > > cleanup code of the DLL, just in case the R user forgets to cleanup. > > How do you make sure the no one uses the now invalid integer value? > There can be many copies of your proxy object around and they > all point to nirvana ... Sorry, that was lack of clarity on my part about what I meant by "persistent". Whenever I use this mechanism, I'm careful to ensure that the C/Delphi objects only have lifetimes *within* a function, and to include an 'on.exit' call to the "destructor"-- I would never create global objects pointing to ephemeral C structures. Admittedly, this relies on programming self-discipline, and has no cast-iron anti-nirvana mechanism! Ross' original query seems very much along these lines, though. If I was really creating global persistent objects, then 'externalptr' would definitely be much better. Where would be best to read about externalptr? I'm having trouble finding material in the manuals or the site-search. And would I need to use all the .Call machinery and C headers and SEXP etc in order to handle externalptr objects? > > Cheers, > Simon bye Mark __ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel
Re: [Rd] external pointers
On Mon, 12 Dec 2005 [EMAIL PROTECTED] wrote: > Hi Simon > > Thanks for that... see below for my feeble counterblasts! (And two > questions.) > > > Mark, > > > > On Dec 12, 2005, at 7:48 AM, <[EMAIL PROTECTED]> wrote: > > > > > (i)The first '.C' call uses Delphi code to allocate (using Delphi's > > > own memory manager) and set up a persistent object that R > > doesn't know > > > about. The Delphi code then returns an "opaque" > > integer-valued handle > > > to R, which is the address of the object in the Delphi DLL's world. > > > > That's a bad idea for a couple of reasons, the main being > > that integer is not guaranteed to be able to hold a pointer - > > it won't work on any 64-bit platform. > > Very true, though 64 bit systems are not a big worry for Delphi 6.0 > writers... ;) I did once speculate about hacking around this sort of > thing by encoding into character strings instead of integers, uggg. > > > Second drawback is that > > you have no way to link the life of the R object to your > > Delphi object, because there is no way gc will tell you that > > the object is gone. This will lead to memory leaks. [Been > > there, done that ;)] Both issues are solved by the external pointers. > > > > > > (iii) There is a final cleanup '.C' call which deallocates the > > > persistent object. I sometimes also automate the destruction in the > > > cleanup code of the DLL, just in case the R user forgets to cleanup. > > > > How do you make sure the no one uses the now invalid integer value? > > There can be many copies of your proxy object around and they > > all point to nirvana ... > > Sorry, that was lack of clarity on my part about what I meant by > "persistent". Whenever I use this mechanism, I'm careful to ensure that > the C/Delphi objects only have lifetimes *within* a function, and to > include an 'on.exit' call to the "destructor"-- I would never create > global objects pointing to ephemeral C structures. Admittedly, this > relies on programming self-discipline, and has no cast-iron anti-nirvana > mechanism! Ross' original query seems very much along these lines, > though. > > If I was really creating global persistent objects, then 'externalptr' > would definitely be much better. > > Where would be best to read about externalptr? I'm having trouble > finding material in the manuals or the site-search. > > And would I need to use all the .Call machinery and C headers and SEXP > etc in order to handle externalptr objects? One package using externalptr is rgdal - Tim Keitt wrote the bindings to the external GDAL library for reading raster images to first return a pointer to a dataset (on disk) opened by GDAL, then to use the object to retrieve (parts of) the data. Most of the .Call/SEXP machinery is there (for the C++ case, GDAL is C++, so GDAL manages its own memory for its objects). The package also uses S4 classes, which may be overkill for your purposes. Roger > > > > > Cheers, > > Simon > > bye > Mark > > __ > R-devel@r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel > -- Roger Bivand Economic Geography Section, Department of Economics, Norwegian School of Economics and Business Administration, Helleveien 30, N-5045 Bergen, Norway. voice: +47 55 95 93 55; fax +47 55 95 95 43 e-mail: [EMAIL PROTECTED] __ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel