digitalmars.D.learn - Is there a weak pointer or references in D?
- Charles Hixson (5/5) Jan 11 2013 I was looking for a way to create a weak reference to either a struct or...
- Era Scarecrow (25/30) Jan 11 2013 Looks like you'll have to create the access yourself, you can
- monarch_dodra (6/9) Jan 11 2013 Honest question: How can you have a weak pointer in a language
- Nekroze (9/11) Jan 11 2013 I beleive the OP means something like pythons weakref
- Era Scarecrow (18/22) Jan 11 2013 I had the impression in the original text you wanted to auto
- Jonathan M Davis (9/23) Jan 11 2013 That doesn't fly with the GC, because then you can have a reference to m...
- thedeemon (14/19) Jan 12 2013 That does fly with GC in languages that are aware of weak
- Era Scarecrow (7/10) Jan 12 2013 There's that, but also what about what if the pointer wasn't a
- Charles Hixson (14/24) Jan 12 2013 You really shouldn't break the type constraints. If you do, then you
- Era Scarecrow (4/7) Jan 12 2013 No; Unless you flag every relevant portion as pointer/non
- thedeemon (5/11) Jan 13 2013 In OCaml, which I was talking about, GC is precise, so there are
- Charles Hixson (45/75) Jan 11 2013 Thanks. That looks quite useful. OTOH, I don't see how the pointer
- Era Scarecrow (25/77) Jan 12 2013 Correct. To create an object if it wasn't there when trying to
- Charles Hixson (22/94) Jan 12 2013 I don't think reference counting would work for my purposes, which is
- Era Scarecrow (13/20) Jan 12 2013 Just off hand I think I'm recalling that in C++ the weak
- =?ISO-8859-1?Q?Alex_R=F8nne_Petersen?= (7/12) Jan 12 2013 https://github.com/lycus/mci/blob/master/src/mci/core/weak.d
- Charles Hixson (7/16) Jan 13 2013 It certainly does have some caveats. And according to at least one of
- =?ISO-8859-1?Q?Alex_R=F8nne_Petersen?= (17/37) Jan 13 2013 Well, I'm not going to lie: You cannot implement weak references in D
- Charles Hixson (8/46) Feb 17 2013 O. To me that sounded like a likely thing for a garbage collector to
I was looking for a way to create a weak reference to either a struct or a class. I need to be able to use it to automatically generate an active reference on access. (I intend to do this by rolling in data from a file.) Any guidance as to where I should look?
Jan 11 2013
On Friday, 11 January 2013 at 18:22:30 UTC, Charles Hixson wrote:I was looking for a way to create a weak reference to either a struct or a class. I need to be able to use it to automatically generate an active reference on access. (I intend to do this by rolling in data from a file.) Any guidance as to where I should look?Looks like you'll have to create the access yourself, you can forward access to the new ptr via a property call by the function you name. This works. struct S { int x; S* _s; //for weak ptr. //constructor details so we can show it's //differences in the lower prints. S* s(int x) { if (_s is null) _s = new S(x); return _s; } void print(){writeln(this);} } S test; test.print(); test.s(10).print(); test.print(); I've tried making a weakPtr template function, however it complains about a nested function call (perhaps cause it was within a unittest); Shows the problem(s) on that side. It's possible to write a mixin that could do those details for you.
Jan 11 2013
On Friday, 11 January 2013 at 21:12:40 UTC, Era Scarecrow wrote:I've tried making a weakPtr template function, however it complains about a nested function call (perhaps cause it was within a unittest); Shows the problem(s) on that side.Honest question: How can you have a weak pointer in a language that is garbage collected? If you mean weak pointer to manually allocated data, wouldn't that imply also already having a shared pointer? AFAIK D doesn't really have that (though it does have RefCounted).
Jan 11 2013
On Friday, 11 January 2013 at 22:07:45 UTC, monarch_dodra wrote:Honest question: How can you have a weak pointer in a language that is garbage collected?I beleive the OP means something like pythons weakref (http://docs.python.org/2/library/weakref.html) that is qoute: A weak reference to an object is not enough to keep the object alive: when the only remaining references to a referent are weak references, garbage collection is free to destroy the referent and reuse its memory for something else. I would like to have no how to do something like this in D aswell as it could be handy.
Jan 11 2013
I had the impression in the original text you wanted to auto allocate memory when accessing the field, not as described here. Might be time to re-watch the remainder of the computer science lectures. On Friday, 11 January 2013 at 23:51:04 UTC, Nekroze wrote:A weak reference to an object is not enough to keep the object alive: when the only remaining references to a referent are weak references, garbage collection is free to destroy the referent and reuse its memory for something else.How very C++'ish of you. With a weak reference as that, memory safety becomes a much larger issue (and you likely can only make system code, I surely wouldn't mark it trusted or safe). It sorta sounds like what slices are in D; Although D's GC won't free memory unless it's sure it isn't in use (rather than the other way around). You might get the desired effect by removing areas from GC's scanning (for active references), but use at your own risk. With that in mind I have the impression you won't find weak pointers in D (or phobos anyways); Or if they are present, then it simply lets the object go once the strong pointers are gone and lets the GC pick it up later (which then weak pointers are pointless as GC does that anyways).
Jan 11 2013
On Saturday, January 12, 2013 00:51:02 Nekroze wrote:On Friday, 11 January 2013 at 22:07:45 UTC, monarch_dodra wrote:That doesn't fly with the GC, because then you can have a reference to memory that's been freed - though I suppose that it could work if the weak reference were set to null when the normal reference was collected. There's no reason that you couldn't do that with ref-counted objects, so perhaps something like that could be done with std.typecons.RefCounted, but we don't currently have anything like that, and you'd still need to make the weak ref null when the normal ref is destroyed, or you'd have memory safety issues. - Jonathan M DavisHonest question: How can you have a weak pointer in a language that is garbage collected?I beleive the OP means something like pythons weakref (http://docs.python.org/2/library/weakref.html) that is qoute: A weak reference to an object is not enough to keep the object alive: when the only remaining references to a referent are weak references, garbage collection is free to destroy the referent and reuse its memory for something else. I would like to have no how to do something like this in D aswell as it could be handy.
Jan 11 2013
On Saturday, 12 January 2013 at 02:49:40 UTC, Jonathan M Davis wrote:That doesn't fly with the GC, because then you can have a reference to memory that's been freed - though I suppose that it could work if the weak reference were set to null when the normal reference was collected.That does fly with GC in languages that are aware of weak pointers. Like OCaml which has a moving GC. From its manual: "A weak pointer is a value that the garbage collector may erase whenever the value is not used any more (through normal pointers) by the program. Note that finalisation functions are run after the weak pointers are erased. A weak pointer is said to be full if it points to a value, empty if the value was erased by the GC." http://caml.inria.fr/pub/docs/manual-ocaml/libref/Weak.html So the runtime is aware of weak pointers and clears them to "empty" state when pointed value dies. I don't see yet how it can be implemented in D without patching its GC.
Jan 12 2013
On Saturday, 12 January 2013 at 10:58:23 UTC, thedeemon wrote:So the runtime is aware of weak pointers and clears them to "empty" state when pointed value dies. I don't see yet how it can be implemented in D without patching its GC.There's that, but also what about what if the pointer wasn't a pointer to the data at all? What it if was a part of a float that determined a calculation for your taxes? Or a series of flags that happen to make that magic number? If they get 'nulled' by the GC, I'd call that a definite bug and problem; Unless the GC can tell apart what is and isn't a pointer to data.
Jan 12 2013
On 01/12/2013 03:27 AM, Era Scarecrow wrote:On Saturday, 12 January 2013 at 10:58:23 UTC, thedeemon wrote:You really shouldn't break the type constraints. If you do, then you must expect problems. But weak pointers do not themselves break type constraints. They do, however, require that the garbage collector cooperate with them. User implemented weak pointers which the garbage collector is unaware of are almost guaranteed to cause problems. The garbage collector needs to know to null them when it frees the storage. And if you store non-pointer data into a pointer, you are asking for trouble in ANY language, but in languages with dynamic storage management you are practically guaranteed to get the trouble you asked for. I languages like C/C++ you can often get away with it...but it's still a "really bad idea"(tm). P.S.: Perhaps you're thinking of unions with a combination of floats and pointers in them. Legal, I think, but still a really bad idea.So the runtime is aware of weak pointers and clears them to "empty" state when pointed value dies. I don't see yet how it can be implemented in D without patching its GC.There's that, but also what about what if the pointer wasn't a pointer to the data at all? What it if was a part of a float that determined a calculation for your taxes? Or a series of flags that happen to make that magic number? If they get 'nulled' by the GC, I'd call that a definite bug and problem; Unless the GC can tell apart what is and isn't a pointer to data.
Jan 12 2013
On Sunday, 13 January 2013 at 00:37:07 UTC, Charles Hixson wrote:P.S.: Perhaps you're thinking of unions with a combination of floats and pointers in them. Legal, I think, but still a really bad idea.No; Unless you flag every relevant portion as pointer/non pointer, then a float can get confused as a pointer. To my understanding, things aren't tagged that way.
Jan 12 2013
On Saturday, 12 January 2013 at 11:27:03 UTC, Era Scarecrow wrote:On Saturday, 12 January 2013 at 10:58:23 UTC, thedeemon wrote:In OCaml, which I was talking about, GC is precise, so there are no false pointers. This is done by tagging: pointers have least significant bit being 0 and non-pointers all have it 1, so native ints in OCaml are one bit smaller than usual (31-bit on x86).So the runtime is aware of weak pointers and clears them to "empty" state when pointed value dies. I don't see yet how it can be implemented in D without patching its GC.There's that, but also what about what if the pointer wasn't a pointer to the data at all?
Jan 13 2013
On 01/11/2013 01:12 PM, Era Scarecrow wrote:On Friday, 11 January 2013 at 18:22:30 UTC, Charles Hixson wrote:Thanks. That looks quite useful. OTOH, I don't see how the pointer allows an item to be freed. You probably meant that this was a framework to start development from. And it does show a way to auto initialize a null pointer (but that's not where I'm hung up...rather on how to automatically null the pointer when the last valid reference is discarded. It looks as if reference counting is the only feasible way, which isn't what I want. I'd need something that the garbage collector cooperated with. If it hasn't been built already, then a customized approach is better...which doesn't involve weak pointers.) But others points are well taken. A weak reference wouldn't be enough by itself, I'd also need to have the garbage collector prefer to collect stale objects. So what I'll probably do is accompany each item in the structure (Not a struct, but also not just a class. More a collection of structs and classes that work together.) with a sequence counter that's episodically advanced. Then at some point I decide that anything that hasn't been touched since some particular sequence is to be freed. And *THEN* I go back through the entire RAM resident structure and either free the items or subtract the current sequence counter value from them, and then reset the sequence counter to the largest remaining value + 1. When freeing, check if the state needs to be saved. That's the rough idea. Weak pointers will make it easier, but no big deal either way. I may follow your guidance on implementing them, but what I was really hoping for was weak references. Used sort of like: Item item = weak(new Item(params)); With Item being a class. Clearly what weak() returned would need to be an instance of a descendant class of Item. Then I could simply maintain a LRU cache of Items, and clear out the old ones, but not free them before the garbage collector decided it was time. The approach I'm now planning on using frees things in a way that is much less sensitive (I suspect) to current memory pressures. OTOH, I'd need to ensure that Items saved their state (if necessary) before being freed anyway. Handling it "externally" allows this to be ensured by something more definite in timing than a destructor. Still, your design for a weak pointer makes it quite easy for an instance to be created if missing. That may be enough advantage that it would be the best way to proceed. Also, I'm really not enamored of template functions, though I am certainly aware of their power. So the design you offered is one that I would prefer over a templated one. (Besides, each class/struct that I want to have a weak pointer to would have a different way of constructing missing versions. So the template would need so much customization, that it wouldn't be much benefit.) The only things I dislike about you design are things I dislike about all designs that use pointers...and I *did* ask for such a design.I was looking for a way to create a weak reference to either a struct or a class. I need to be able to use it to automatically generate an active reference on access. (I intend to do this by rolling in data from a file.) Any guidance as to where I should look?Looks like you'll have to create the access yourself, you can forward access to the new ptr via a property call by the function you name. This works. struct S { int x; S* _s; //for weak ptr. //constructor details so we can show it's //differences in the lower prints. S* s(int x) { if (_s is null) _s = new S(x); return _s; } void print(){writeln(this);} } S test; test.print(); test.s(10).print(); test.print(); I've tried making a weakPtr template function, however it complains about a nested function call (perhaps cause it was within a unittest); Shows the problem(s) on that side. It's possible to write a mixin that could do those details for you.
Jan 11 2013
On Saturday, 12 January 2013 at 04:41:00 UTC, Charles Hixson wrote:Thanks. That looks quite useful. OTOH, I don't see how the pointer allows an item to be freed. You probably meant that this was a framework to start development from.Correct. To create an object if it wasn't there when trying to access it basically. That's what I originally thought you wanted; nothing about freeing it.And it does show a way to auto initialize a null pointer (but that's not where I'm hung up...rather on how to automatically null the pointer when the last valid reference is discarded. It looks as if reference counting is the only feasible way, which isn't what I want. I'd need something that the garbage collector cooperated with. If it hasn't been built already, then a customized approach is better...which doesn't involve weak pointers.) But others points are well taken. A weak reference wouldn't be enough by itself, I'd also need to have the garbage collector prefer to collect stale objects. So what I'll probably do is accompany each item in the structure (Not a struct, but also not just a class. More a collection of structs and classes that work together.) with a sequence counter that's episodically advanced. Then at some point I decide that anything that hasn't been touched since some particular sequence is to be freed. And *THEN* I go back through the entire RAM resident structure and either free the items or subtract the current sequence counter value from them, and then reset the sequence counter to the largest remaining value + 1. When freeing, check if the state needs to be saved.Hmmmm... I'd just stay with reference counting. If you leave scope with a struct it's destructor is handled (and refcounting), if it's a class, then it remains 'stale' until the GC collects it, then refcounting is updated as everything else is destroyed.That's the rough idea. Weak pointers will make it easier, but no big deal either way. I may follow your guidance on implementing them, but what I was really hoping for was weak references. Used sort of like: Item item = weak(new Item(params));Best if you don't... A sorta nice idea, but we don't need to be duplicating more of C++'s (boost's?) mistakes.With Item being a class. Clearly what weak() returned would need to be an instance of a descendant class of Item. Then I could simply maintain a LRU cache of Items, and clear out the old ones, but not free them before the garbage collector decided it was time. The approach I'm now planning on using frees things in a way that is much less sensitive (I suspect) to current memory pressures. OTOH, I'd need to ensure that Items saved their state (if necessary) before being freed anyway. Handling it "externally" allows this to be ensured by something more definite in timing than a destructor. Still, your design for a weak pointer makes it quite easy for an instance to be created if missing. That may be enough advantage that it would be the best way to proceed. Also, I'm really not enamored of template functions, though I am certainly aware of their power. So the design you offered is one that I would prefer over a templated one. (Besides, each class/struct that I want to have a weak pointer to would have a different way of constructing missing versions. So the template would need so much customization, that it wouldn't be much benefit.)The template one, (should it have worked) would have had a signature of: T* weakPtr(T, V...)(ref T* ptr, V args); //V being default arguments (if any) How it would need to be more customizable I don't know; Alternatively a delegate could have been included making only a lamba needed in key locations.The only things I dislike about you design are things I dislike about all designs that use pointers...and I *did* ask for such a design.Yes you did. But since you can't use 'ref' as part of a variable's signature (outside of function declarations) you'd have to to use pointers instead. Just try to be as safe as possible. With pointer arithmetic being unsafe and mostly unused (unneeded due to the arrays) it's just a matter of allocating and accessing the pointer that's safe (or as much as using classes anyways).
Jan 12 2013
On 01/12/2013 02:04 AM, Era Scarecrow wrote:On Saturday, 12 January 2013 at 04:41:00 UTC, Charles Hixson wrote:I don't think reference counting would work for my purposes, which is why I wanted a "weak pointer". There will usually be many live references at the time I need to release an item. If I'd had weak pointers I could have made almost all of them weak pointers. I want to release things that are stale, not things that are unreferenced. I was trying to avoid needing to cycle through the entire data structure.Thanks. That looks quite useful. OTOH, I don't see how the pointer allows an item to be freed. You probably meant that this was a framework to start development from.Correct. To create an object if it wasn't there when trying to access it basically. That's what I originally thought you wanted; nothing about freeing it.And it does show a way to auto initialize a null pointer (but that's not where I'm hung up...rather on how to automatically null the pointer when the last valid reference is discarded. It looks as if reference counting is the only feasible way, which isn't what I want. I'd need something that the garbage collector cooperated with. If it hasn't been built already, then a customized approach is better...which doesn't involve weak pointers.) But others points are well taken. A weak reference wouldn't be enough by itself, I'd also need to have the garbage collector prefer to collect stale objects. So what I'll probably do is accompany each item in the structure (Not a struct, but also not just a class. More a collection of structs and classes that work together.) with a sequence counter that's episodically advanced. Then at some point I decide that anything that hasn't been touched since some particular sequence is to be freed. And *THEN* I go back through the entire RAM resident structure and either free the items or subtract the current sequence counter value from them, and then reset the sequence counter to the largest remaining value + 1. When freeing, check if the state needs to be saved.Hmmmm... I'd just stay with reference counting. If you leave scope with a struct it's destructor is handled (and refcounting), if it's a class, then it remains 'stale' until the GC collects it, then refcounting is updated as everything else is destroyed.Well, it doesn't exist, so no problem. But what about that is a mistake? I haven't used enough C++ to know. (My recent background is Python, Java, and Ruby...C is way in the background, and the last time I used C++ heavily was before the STL.)That's the rough idea. Weak pointers will make it easier, but no big deal either way. I may follow your guidance on implementing them, but what I was really hoping for was weak references. Used sort of like: Item item = weak(new Item(params));Best if you don't... A sorta nice idea, but we don't need to be duplicating more of C++'s (boost's?) mistakes.Some of the items have heavy data inclusions, and they would get passed around as pointers, some of them are light, and they'd be structs. Some could be automatically calculated from the creation parameters, others need to be read in from files. And these cause different values returned from functions doing abstractly the same job.With Item being a class. Clearly what weak() returned would need to be an instance of a descendant class of Item. Then I could simply maintain a LRU cache of Items, and clear out the old ones, but not free them before the garbage collector decided it was time. The approach I'm now planning on using frees things in a way that is much less sensitive (I suspect) to current memory pressures. OTOH, I'd need to ensure that Items saved their state (if necessary) before being freed anyway. Handling it "externally" allows this to be ensured by something more definite in timing than a destructor. Still, your design for a weak pointer makes it quite easy for an instance to be created if missing. That may be enough advantage that it would be the best way to proceed. Also, I'm really not enamored of template functions, though I am certainly aware of their power. So the design you offered is one that I would prefer over a templated one. (Besides, each class/struct that I want to have a weak pointer to would have a different way of constructing missing versions. So the template would need so much customization, that it wouldn't be much benefit.)The template one, (should it have worked) would have had a signature of: T* weakPtr(T, V...)(ref T* ptr, V args); //V being default arguments (if any) How it would need to be more customizable I don't know; Alternatively a delegate could have been included making only a lamba needed in key locations.If I'd been able to have actual weak pointers, that would be worthwhile. As it is...I'm going to use references (i.e., class instances) as the external interfaces. Internally, things will often be quite a bit different. (Yeah, maybe I should say handle rather than reference. I'm not sure. I *am* sure I like the syntax of class instances a lot better than I do pointers to structs.)The only things I dislike about you design are things I dislike about all designs that use pointers...and I *did* ask for such a design.Yes you did. But since you can't use 'ref' as part of a variable's signature (outside of function declarations) you'd have to to use pointers instead. Just try to be as safe as possible. With pointer arithmetic being unsafe and mostly unused (unneeded due to the arrays) it's just a matter of allocating and accessing the pointer that's safe (or as much as using classes anyways).
Jan 12 2013
On Sunday, 13 January 2013 at 00:56:59 UTC, Charles Hixson wrote:I don't think reference counting would work for my purposes, which is why I wanted a "weak pointer". There will usually be many live references at the time I need to release an item. If I'd had weak pointers I could have made almost all of them weak pointers. I want to release things that are stale, not things that are unreferenced. I was trying to avoid needing to cycle through the entire data structure.Just off hand I think I'm recalling that in C++ the weak pointers were related and part of the main reference counting; An allocated (heap) control block handled the references and memory. If then you were to extended a second number to represent weak pointers, they would be for when the control block could free itself (vs the data with the strong pointers). But the GC wouldn't be part of it most likely unless the control block itself was leaked in it's entirety. That might be safe (mostly); In those cases you'd have to test the control block which would tell you if the pointer was still valid or not. Well I got my hands full so I won't be the to touch this possible implementation; At least for a while.
Jan 12 2013
On 11-01-2013 19:15, Charles Hixson wrote:I was looking for a way to create a weak reference to either a struct or a class. I need to be able to use it to automatically generate an active reference on access. (I intend to do this by rolling in data from a file.) Any guidance as to where I should look?https://github.com/lycus/mci/blob/master/src/mci/core/weak.d It has some caveats (see the comments). -- Alex Rønne Petersen alex alexrp.com / alex lycus.org http://lycus.org
Jan 12 2013
On 01/12/2013 09:24 PM, Alex Rønne Petersen wrote:On 11-01-2013 19:15, Charles Hixson wrote:It certainly does have some caveats. And according to at least one of them it may break badly in the future from a plausible compiler change. Well, it's what I asked for, but using something that can be expected to break without warning. I want to write code that I can forget after I test. It would have been a great convenience, but that's a bit too high a price to pay for a convenience.I was looking for a way to create a weak reference to either a struct or a class. I need to be able to use it to automatically generate an active reference on access. (I intend to do this by rolling in data from a file.) Any guidance as to where I should look?https://github.com/lycus/mci/blob/master/src/mci/core/weak.d It has some caveats (see the comments).
Jan 13 2013
On 14-01-2013 00:18, Charles Hixson wrote:On 01/12/2013 09:24 PM, Alex Rønne Petersen wrote:Well, I'm not going to lie: You cannot implement weak references in D any other way. The GC just isn't helpful enough. The only way this code could break is if D ever gets a copying or compacting GC. The chances of that happening, ever, are practically nil because such GCs are extremely impractical in natively-compiled systems languages. Otherwise all you have to be aware of in your code is that the referenced object cannot be used as a mutex in synchronized statements and cannot have custom dispose events (finalizers). (Note, the last part there doesn't mean that the referenced object can't have a finalizer declared via `~this()` - it just means that you should not dynamically attach finalizers to it with rt_attachDisposeEvent().) -- Alex Rønne Petersen alex alexrp.com / alex lycus.org http://lycus.orgOn 11-01-2013 19:15, Charles Hixson wrote:It certainly does have some caveats. And according to at least one of them it may break badly in the future from a plausible compiler change. Well, it's what I asked for, but using something that can be expected to break without warning. I want to write code that I can forget after I test. It would have been a great convenience, but that's a bit too high a price to pay for a convenience.I was looking for a way to create a weak reference to either a struct or a class. I need to be able to use it to automatically generate an active reference on access. (I intend to do this by rolling in data from a file.) Any guidance as to where I should look?https://github.com/lycus/mci/blob/master/src/mci/core/weak.d It has some caveats (see the comments).
Jan 13 2013
On 01/13/2013 09:01 PM, Alex Rønne Petersen wrote:On 14-01-2013 00:18, Charles Hixson wrote:O. To me that sounded like a likely thing for a garbage collector to have added.On 01/12/2013 09:24 PM, Alex Rønne Petersen wrote:Well, I'm not going to lie: You cannot implement weak references in D any other way. The GC just isn't helpful enough. The only way this code could break is if D ever gets a copying or compacting GC. The chances of that happening, ever, are practically nil because such GCs are extremely impractical in natively-compiled systems languages.On 11-01-2013 19:15, Charles Hixson wrote:It certainly does have some caveats. And according to at least one of them it may break badly in the future from a plausible compiler change. Well, it's what I asked for, but using something that can be expected to break without warning. I want to write code that I can forget after I test. It would have been a great convenience, but that's a bit too high a price to pay for a convenience.I was looking for a way to create a weak reference to either a struct or a class. I need to be able to use it to automatically generate an active reference on access. (I intend to do this by rolling in data from a file.) Any guidance as to where I should look?https://github.com/lycus/mci/blob/master/src/mci/core/weak.d It has some caveats (see the comments).Otherwise all you have to be aware of in your code is that the referenced object cannot be used as a mutex in synchronized statements and cannot have custom dispose events (finalizers).Ok, but that's a thing that's already in place. I was worried about code that I wrote breaking with a new version of the compiler, perhaps a few years after I'd stopped thinking about it.(Note, the last part there doesn't mean that the referenced object can't have a finalizer declared via `~this()` - it just means that you should not dynamically attach finalizers to it with rt_attachDisposeEvent().)Thanks. That's an important clarification, as I would otherwise have misunderstood it.
Feb 17 2013