www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - DIP74: Reference Counted Class Objects

reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
http://wiki.dlang.org/DIP74 got to reviewable form. Please destroy and 
discuss.

Thanks,

Andrei
Feb 26 2015
next sibling parent reply "weaselcat" <weaselcat gmail.com> writes:
On Thursday, 26 February 2015 at 21:50:56 UTC, Andrei 
Alexandrescu wrote:
 http://wiki.dlang.org/DIP74 got to reviewable form. Please 
 destroy and discuss.

 Thanks,

 Andrei
So is the end game of dip25 and dip74 to not have to wrap types you intend to manage with RC like C++ but just design the classes/structs themselves around being RCed from the start?
Feb 26 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/26/15 2:01 PM, weaselcat wrote:
 On Thursday, 26 February 2015 at 21:50:56 UTC, Andrei Alexandrescu wrote:
 http://wiki.dlang.org/DIP74 got to reviewable form. Please destroy and
 discuss.

 Thanks,

 Andrei
So is the end game of dip25 and dip74 to not have to wrap types you intend to manage with RC like C++ but just design the classes/structs themselves around being RCed from the start?
That is correct. Well as shown there are ways to design classes that work both with RC and GC. -- Andrei
Feb 26 2015
parent reply "Kagamin" <spam here.lot> writes:
On Thursday, 26 February 2015 at 22:02:51 UTC, Andrei 
Alexandrescu wrote:
 So is the end game of dip25 and dip74 to not have to wrap 
 types you
 intend to manage with RC like C++ but just design the 
 classes/structs
 themselves around being RCed from the start?
That is correct. Well as shown there are ways to design classes that work both with RC and GC. -- Andrei
If a class is meant to be refcounted at compile time, what's a difference from alias MyClass = RefCounted!MyClassImpl; // use MyClass instead except for it introduces an additional check for null and a branch?
Feb 27 2015
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/27/15 12:53 AM, Kagamin wrote:
 On Thursday, 26 February 2015 at 22:02:51 UTC, Andrei Alexandrescu wrote:
 So is the end game of dip25 and dip74 to not have to wrap types you
 intend to manage with RC like C++ but just design the classes/structs
 themselves around being RCed from the start?
That is correct. Well as shown there are ways to design classes that work both with RC and GC. -- Andrei
If a class is meant to be refcounted at compile time, what's a difference from alias MyClass = RefCounted!MyClassImpl; // use MyClass instead except for it introduces an additional check for null and a branch?
The typechecking on RCOs is stricter, which makes them safe. -- Andrei
Feb 27 2015
prev sibling next sibling parent reply "Brian Schott" <briancschott gmail.com> writes:
On Thursday, 26 February 2015 at 21:50:56 UTC, Andrei 
Alexandrescu wrote:
 http://wiki.dlang.org/DIP74 got to reviewable form. Please 
 destroy and discuss.

 Thanks,

 Andrei
One of the first things that stood out to me is that "add ref" is two words and "release" is one. For the sake of symmetry, how about these: * opIncRef, opDecRef * opAcquire, opRelease The DIP states that "Any attributes are allowed on these methods.", but later states "The complexity of this code underlies the importance of making opAddRef and especially opRelease nothrow". Should the DIP require that these two functions be marked nothrow?
Feb 26 2015
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/26/15 2:03 PM, Brian Schott wrote:
 One of the first things that stood out to me is that "add ref" is two
 words and "release" is one. For the sake of symmetry, how about these:
 *  opIncRef, opDecRef
 *  opAcquire, opRelease
All - please PLEASE do not derail this into yet another debate about which names are best. -- Andrei
Feb 26 2015
parent reply "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Thursday, 26 February 2015 at 22:04:09 UTC, Andrei 
Alexandrescu wrote:
 On 2/26/15 2:03 PM, Brian Schott wrote:
 One of the first things that stood out to me is that "add ref" 
 is two
 words and "release" is one. For the sake of symmetry, how 
 about these:
 *  opIncRef, opDecRef
 *  opAcquire, opRelease
All - please PLEASE do not derail this into yet another debate about which names are best. -- Andrei
Using protocols rather than enforcing a particular implementation is nice, but D needs to stop reinventing terminology and syntax matters. Acquire/Release: https://msdn.microsoft.com/en-us/library/windows/hardware/ff540496%28v=vs.85%29.aspx Retain/Release: https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html AutoRelease pools / Drain: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSAutoreleasePool_Class/index.html#//apple_ref/occ/instm/NSAutoreleasePool/drain Antonyms for "release": http://www.merriam-webster.com/thesaurus/release[verb]
Feb 27 2015
next sibling parent reply "Kagamin" <spam here.lot> writes:
On Friday, 27 February 2015 at 08:26:14 UTC, Ola Fosheim Grøstad 
wrote:
 Acquire/Release:

 https://msdn.microsoft.com/en-us/library/windows/hardware/ff540496%28v=vs.85%29.aspx
That's about cache coherency, reference counting is only an illustration. And this is about reference counting: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680509.aspx
Feb 27 2015
parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Friday, 27 February 2015 at 08:56:49 UTC, Kagamin wrote:
 On Friday, 27 February 2015 at 08:26:14 UTC, Ola Fosheim 
 Grøstad wrote:
 Acquire/Release:

 https://msdn.microsoft.com/en-us/library/windows/hardware/ff540496%28v=vs.85%29.aspx
That's about cache coherency, reference counting is only an illustration. And this is about reference counting: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680509.aspx
Yeah, and that page documents why the Bill Gatish Microsoft sucks. They used to invent their own incoherent standards/terminology...
Feb 27 2015
prev sibling parent reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Friday, 27 February 2015 at 08:26:14 UTC, Ola Fosheim Grøstad 
wrote:
 On Thursday, 26 February 2015 at 22:04:09 UTC, Andrei 
 Alexandrescu wrote:
 On 2/26/15 2:03 PM, Brian Schott wrote:
 One of the first things that stood out to me is that "add 
 ref" is two
 words and "release" is one. For the sake of symmetry, how 
 about these:
 *  opIncRef, opDecRef
 *  opAcquire, opRelease
All - please PLEASE do not derail this into yet another debate about which names are best. -- Andrei
Using protocols rather than enforcing a particular implementation is nice, but D needs to stop reinventing terminology and syntax matters. -- snip --
AddRef/Release is established COM terminology.
Feb 27 2015
next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Friday, 27 February 2015 at 13:36:33 UTC, Marc Schütz wrote:
 AddRef/Release is established COM terminology.
Which is from 1993, a period of time where MS was completely ignorant of everything outside MS. Common resource-access terminology is: acquire/release retain/release inc_ref/dec_ref add_ref/remove_ref down/up wait/signal P/V open/close enter/exit begin/end … Notice the symmetry?
Feb 27 2015
prev sibling parent reply David Gileadi <gileadis NSPMgmail.com> writes:
On 2/27/15 6:36 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net>" 
wrote:
 On Friday, 27 February 2015 at 08:26:14 UTC, Ola Fosheim Grøstad wrote:
 On Thursday, 26 February 2015 at 22:04:09 UTC, Andrei Alexandrescu wrote:
 On 2/26/15 2:03 PM, Brian Schott wrote:
 One of the first things that stood out to me is that "add ref" is two
 words and "release" is one. For the sake of symmetry, how about these:
 *  opIncRef, opDecRef
 *  opAcquire, opRelease
All - please PLEASE do not derail this into yet another debate about which names are best. -- Andrei
Using protocols rather than enforcing a particular implementation is nice, but D needs to stop reinventing terminology and syntax matters. -- snip --
AddRef/Release is established COM terminology.
One reason for keeping COM terminology might be if std.c.windows.com.IUnknown can automatically take advantage of DIP74. Of course this could also be a downside—would DIP74 break existing COM code in D?
Feb 27 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/27/15 10:34 AM, David Gileadi wrote:
 On 2/27/15 6:36 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net>"
 wrote:
 On Friday, 27 February 2015 at 08:26:14 UTC, Ola Fosheim Grøstad wrote:
 On Thursday, 26 February 2015 at 22:04:09 UTC, Andrei Alexandrescu
 wrote:
 On 2/26/15 2:03 PM, Brian Schott wrote:
 One of the first things that stood out to me is that "add ref" is two
 words and "release" is one. For the sake of symmetry, how about these:
 *  opIncRef, opDecRef
 *  opAcquire, opRelease
All - please PLEASE do not derail this into yet another debate about which names are best. -- Andrei
Using protocols rather than enforcing a particular implementation is nice, but D needs to stop reinventing terminology and syntax matters. -- snip --
AddRef/Release is established COM terminology.
One reason for keeping COM terminology might be if std.c.windows.com.IUnknown can automatically take advantage of DIP74. Of course this could also be a downside—would DIP74 break existing COM code in D?
I explicitly avoided the COM names in order to avoid potential confusion and code breakage. People can easily add IUnknownAuto that does the forwarding. -- Andrei
Feb 27 2015
parent reply Jacob Carlborg <doob me.com> writes:
On 2015-02-27 19:38, Andrei Alexandrescu wrote:

 I explicitly avoided the COM names in order to avoid potential confusion
 and code breakage. People can easily add IUnknownAuto that does the
 forwarding. -- Andrei
It's still a breaking change. See one of my other replies [1] for a possible solution. [1] http://forum.dlang.org/post/mcp5nu$1nus$1 digitalmars.com -- /Jacob Carlborg
Feb 27 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/27/15 11:58 AM, Jacob Carlborg wrote:
 On 2015-02-27 19:38, Andrei Alexandrescu wrote:

 I explicitly avoided the COM names in order to avoid potential confusion
 and code breakage. People can easily add IUnknownAuto that does the
 forwarding. -- Andrei
It's still a breaking change. See one of my other replies [1] for a possible solution. [1] http://forum.dlang.org/post/mcp5nu$1nus$1 digitalmars.com
I'm fine with breaking code of people who happen to use the names opAddRef and opRelease. -- Andrei
Feb 27 2015
next sibling parent reply "weaselcat" <weaselcat gmail.com> writes:
On Friday, 27 February 2015 at 20:04:27 UTC, Andrei Alexandrescu 
wrote:
 On 2/27/15 11:58 AM, Jacob Carlborg wrote:
 On 2015-02-27 19:38, Andrei Alexandrescu wrote:

 I explicitly avoided the COM names in order to avoid 
 potential confusion
 and code breakage. People can easily add IUnknownAuto that 
 does the
 forwarding. -- Andrei
It's still a breaking change. See one of my other replies [1] for a possible solution. [1] http://forum.dlang.org/post/mcp5nu$1nus$1 digitalmars.com
I'm fine with breaking code of people who happen to use the names opAddRef and opRelease. -- Andrei
Are op* considered reserved member names?
Feb 27 2015
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/27/15 12:13 PM, weaselcat wrote:
 On Friday, 27 February 2015 at 20:04:27 UTC, Andrei Alexandrescu wrote:
 On 2/27/15 11:58 AM, Jacob Carlborg wrote:
 On 2015-02-27 19:38, Andrei Alexandrescu wrote:

 I explicitly avoided the COM names in order to avoid potential
 confusion
 and code breakage. People can easily add IUnknownAuto that does the
 forwarding. -- Andrei
It's still a breaking change. See one of my other replies [1] for a possible solution. [1] http://forum.dlang.org/post/mcp5nu$1nus$1 digitalmars.com
I'm fine with breaking code of people who happen to use the names opAddRef and opRelease. -- Andrei
Are op* considered reserved member names?
No. -- Andrei
Feb 27 2015
prev sibling parent reply ketmar <ketmar ketmar.no-ip.org> writes:
On Fri, 27 Feb 2015 20:13:31 +0000, weaselcat wrote:

 Are op* considered reserved member names?
no. that's just the "we can break your code, and you can't break ours!"=20 it's funny how the argument "we will not break user's code" pops up even=20 for breaking invalid code, but completely ignored for perfectly valid=20 code not forbidden by the specs.=
Feb 27 2015
parent reply "deadalnix" <deadalnix gmail.com> writes:
On Saturday, 28 February 2015 at 03:49:04 UTC, ketmar wrote:
 On Fri, 27 Feb 2015 20:13:31 +0000, weaselcat wrote:

 Are op* considered reserved member names?
no. that's just the "we can break your code, and you can't break ours!" it's funny how the argument "we will not break user's code" pops up even for breaking invalid code, but completely ignored for perfectly valid code not forbidden by the specs.
I think this is justified to break the code here, but I share the irritation in front of the inconsistency.
Feb 27 2015
next sibling parent reply "Paolo Invernizzi" <paolo.invernizzi no.address> writes:
On Saturday, 28 February 2015 at 05:57:19 UTC, deadalnix wrote:
 On Saturday, 28 February 2015 at 03:49:04 UTC, ketmar wrote:
 On Fri, 27 Feb 2015 20:13:31 +0000, weaselcat wrote:

 Are op* considered reserved member names?
no. that's just the "we can break your code, and you can't break ours!" it's funny how the argument "we will not break user's code" pops up even for breaking invalid code, but completely ignored for perfectly valid code not forbidden by the specs.
I think this is justified to break the code here, but I share the irritation in front of the inconsistency.
I agree, as, well, this is starting to look pretty grotesque... The druntime/phobos 2.067 are breaking every piece of software out there that relies on core.sync or concurrency.scheduler, vibe and tango included. I admit that breakages coming from phobos' changes are pretty different from a breakages coming from compiler changes, but we are talking about the runtime library also. Oh well, who cares: my backlog of D code tasks at work is too long to start complaining... let's go back to the code... --- Paolo
Feb 28 2015
next sibling parent reply "Daniel Murphy" <yebbliesnospam gmail.com> writes:
"Paolo Invernizzi"  wrote in message 
news:wkcsqtzjqybortkabpkv forum.dlang.org...

 The druntime/phobos 2.067 are breaking every piece of software out there 
 that relies on core.sync or concurrency.scheduler, vibe and tango 
 included.
This is an exaggeration...
Feb 28 2015
parent reply "Paolo Invernizzi" <paolo.invernizzi no.address> writes:
On Saturday, 28 February 2015 at 10:30:55 UTC, Daniel Murphy 
wrote:
 "Paolo Invernizzi"  wrote in message 
 news:wkcsqtzjqybortkabpkv forum.dlang.org...

 The druntime/phobos 2.067 are breaking every piece of software 
 out there that relies on core.sync or concurrency.scheduler, 
 vibe and tango included.
This is an exaggeration...
This is reality: both actual version of vibe.d and tango can't be compiled with 2.067, and it's a reality that this put some real work to do on the shoulders of the maintainers. --- Paolo
Feb 28 2015
parent reply "Daniel Murphy" <yebbliesnospam gmail.com> writes:
"Paolo Invernizzi"  wrote in message 
news:avsvjanhckbcjttaolwc forum.dlang.org...

 The druntime/phobos 2.067 are breaking every piece of software out there 
 that relies on core.sync or concurrency.scheduler,
 This is reality: both actual version of vibe.d and tango can't be compiled 
 with 2.067, and it's a reality that this put some real work to do on the 
 shoulders of the maintainers.
Every project that overrides those methods is far from every project that relies on core.sync or core.scheduler.
Feb 28 2015
parent "Paolo Invernizzi" <paolo.invernizzi no.address> writes:
On Saturday, 28 February 2015 at 11:03:14 UTC, Daniel Murphy 
wrote:
 "Paolo Invernizzi"  wrote in message 
 news:avsvjanhckbcjttaolwc forum.dlang.org...

 The druntime/phobos 2.067 are breaking every piece of 
 software out there that relies on core.sync or 
 concurrency.scheduler,
 This is reality: both actual version of vibe.d and tango can't 
 be compiled with 2.067, and it's a reality that this put some 
 real work to do on the shoulders of the maintainers.
Every project that overrides those methods is far from every project that relies on core.sync or core.scheduler.
I agree with you in that. /P
Feb 28 2015
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2015-02-28 10:41, Paolo Invernizzi wrote:

 I agree, as, well, this is starting to look pretty grotesque...

 The druntime/phobos 2.067 are breaking every piece of software out there
 that relies on core.sync or concurrency.scheduler, vibe and tango included.
Add DWT to that list. -- /Jacob Carlborg
Feb 28 2015
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2015-02-28 06:57, deadalnix wrote:

 I think this is justified to break the code here, but I share the
 irritation in front of the inconsistency.
I don't think so because it's so easy to making it a non-breaking change, i.e. require a compiler recognized UDA to enable the functionality. -- /Jacob Carlborg
Feb 28 2015
prev sibling next sibling parent "Matthias Bentrup" <matthias.bentrup googlemail.com> writes:
When a function makes/destroys multiple references to an object 
it should always be safe to coalesce all AddRefs into the first 
AddRef and all Releases to into the last Release call.

This could be a small performance win, but opAddRef/opRelease 
would need the count as argument or maybe as template parameter.
Feb 27 2015
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2015-02-27 21:04, Andrei Alexandrescu wrote:

 I'm fine with breaking code of people who happen to use the names
 opAddRef and opRelease. -- Andrei
I don't think so because it's so easy to making it a non-breaking change, i.e. require a compiler recognized UDA to enable the functionality. -- /Jacob Carlborg
Feb 28 2015
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/26/15 2:03 PM, Brian Schott wrote:
 The DIP states that "Any attributes are allowed on these methods.", but
 later states "The complexity of this code underlies the importance of
 making opAddRef and especially opRelease nothrow". Should the DIP
 require that these two functions be marked nothrow?
It's a liberty still left to user code. -- Andrei
Feb 26 2015
parent reply Nick Treleaven <ntrel-pub mybtinternet.com> writes:
On 26/02/2015 22:04, Andrei Alexandrescu wrote:
 On 2/26/15 2:03 PM, Brian Schott wrote:
 The DIP states that "Any attributes are allowed on these methods.", but
 later states "The complexity of this code underlies the importance of
 making opAddRef and especially opRelease nothrow". Should the DIP
 require that these two functions be marked nothrow?
It's a liberty still left to user code. -- Andrei
ISTM nothrow would be a sensible starting point. That would simplify compiler implementation and avoid invisible inefficiency in user code. Shouldn't we wait for a compelling use case for throwing in these functions before supporting it?
Feb 27 2015
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/27/15 9:24 AM, Nick Treleaven wrote:
 On 26/02/2015 22:04, Andrei Alexandrescu wrote:
 On 2/26/15 2:03 PM, Brian Schott wrote:
 The DIP states that "Any attributes are allowed on these methods.", but
 later states "The complexity of this code underlies the importance of
 making opAddRef and especially opRelease nothrow". Should the DIP
 require that these two functions be marked nothrow?
It's a liberty still left to user code. -- Andrei
ISTM nothrow would be a sensible starting point. That would simplify compiler implementation and avoid invisible inefficiency in user code. Shouldn't we wait for a compelling use case for throwing in these functions before supporting it?
I don't know of a compelling use case. Note that quite a few of the implementations complications remain; the surrounding code may still throw. -- Andrei
Feb 27 2015
prev sibling next sibling parent reply "Brian Schott" <briancschott gmail.com> writes:
On Thursday, 26 February 2015 at 21:50:56 UTC, Andrei 
Alexandrescu wrote:
 http://wiki.dlang.org/DIP74 got to reviewable form. Please 
 destroy and discuss.

 Thanks,

 Andrei
"This lowering assumes left-to-right evaluation of function parameters." -DIP 74 "The following binary expressions are evaluated in an implementation-defined order: AssignExpression, function arguments" - http://dlang.org/expression.html
Feb 26 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/26/15 2:17 PM, Brian Schott wrote:
 On Thursday, 26 February 2015 at 21:50:56 UTC, Andrei Alexandrescu wrote:
 http://wiki.dlang.org/DIP74 got to reviewable form. Please destroy and
 discuss.

 Thanks,

 Andrei
"This lowering assumes left-to-right evaluation of function parameters." -DIP 74 "The following binary expressions are evaluated in an implementation-defined order: AssignExpression, function arguments" - http://dlang.org/expression.html
Yah, Walter mentioned these. We need to fix them. -- Andrei
Feb 26 2015
parent "Brian Schott" <briancschott gmail.com> writes:
On Thursday, 26 February 2015 at 22:22:53 UTC, Andrei 
Alexandrescu wrote:
 Yah, Walter mentioned these. We need to fix them. -- Andrei
https://issues.dlang.org/show_bug.cgi?id=14228
Feb 26 2015
prev sibling next sibling parent reply Johannes Pfau <nospam example.com> writes:
Am Thu, 26 Feb 2015 13:50:55 -0800
schrieb Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>:

 http://wiki.dlang.org/DIP74 got to reviewable form. Please destroy
 and discuss.
 
 Thanks,
 
 Andrei
Looks very nice, some things to refine: "Any attributes are allowed on these methods." * Should safe and trusted by disallowed as " safe code may not issue explicit calls to opAddRef/opRelease"? * Probably also add a note here that the functions must be inverse and a note that they should be nothrow and/or final for performance. "This DIP proposes safe reference counted class objects (including exceptions)" * Unfortunately the DIP doesn't talk about exceptions ;-) Will we simply make Throwable a RCO? "considers that opRelease is the inverse of opAddRef, and therefore is at liberty to elide pairs of calls" * Nice, but does that mean that reference-counted classes are now superior to reference counted structs? It would be nice if the compiler could also detect opRelease/opAddRef in structs. We could still require user code to call these manually in postblits etc but recognizing them would allow eliding pairs. Also a more general question: What are the most important memory management strategies and which are handled by DIP25+DIP74? * GC Of course supported * RC Supported with DIP74. I think this could also be considered as ARC. If not, what is missing from DIP74 compared to ARC? * Scoped (useful for stack objects) Can 'return' be used to implement something which allocates a class on the stack and prevents escaping references? I guess a Scope struct allocating in place + a function returning a reference to the class with 'return' (+ alias this) would work? * Owned Supported by the member variables lifetime = parent lifetime rule? * Unique ? * ?
Feb 26 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/26/15 2:39 PM, Johannes Pfau wrote:
 Looks very nice, some things to refine:

 "Any attributes are allowed on these methods."
 * Should  safe and  trusted by disallowed as
    " safe code may not issue explicit calls to
     opAddRef/opRelease"?
 * Probably also add a note here that the functions must be inverse and
    a note that they should be nothrow and/or final for performance.
OK. I don't want to impose many limitations - let users explore possibilities. I added the recommendation.
 "This DIP proposes  safe reference counted class objects (including
 exceptions)"
 * Unfortunately the DIP doesn't talk about exceptions ;-) Will we
    simply make Throwable a RCO?
Yes.
 "considers that opRelease is the inverse of opAddRef, and therefore is
 at liberty to elide pairs of calls"
 * Nice, but does that mean that reference-counted classes are now
    superior to reference counted structs? It would be nice if the
    compiler could also detect opRelease/opAddRef in structs. We could
    still require user code to call these manually in postblits etc but
    recognizing them would allow eliding pairs.
That's already taken care of - this(this) and ~this() are considered complementary.
 Also a more general question: What are the most important memory
 management strategies and which are handled by DIP25+DIP74?
 * GC
    Of course supported
 * RC
    Supported with DIP74. I think this could also be considered as ARC.
    If not, what is missing from DIP74 compared to ARC?
Unless something major we didn't think of is found with DIP25 and DIP74, it's not impossible we found the perfect shade. Not only we'll offer automatic reference counting, but we'll allow people do define types that are usable in safe code that do that.
 * Scoped (useful for stack objects)
    Can 'return' be used to implement something which allocates a class
    on the stack and prevents escaping references? I guess a Scope
    struct allocating in place + a function returning a reference to the
    class with 'return' (+ alias this) would work?
Yah, DIP74 can be directly used to make "scope w = new Widget;" work. But we'll address that in a distinct DIP in order to not bloat this one.
 * Owned
    Supported by the member variables lifetime = parent lifetime rule?
 * Unique
    ?
 * ?
Let's see. Andrei
Feb 26 2015
parent reply Johannes Pfau <nospam example.com> writes:
Am Thu, 26 Feb 2015 14:53:16 -0800
schrieb Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>:

 On 2/26/15 2:39 PM, Johannes Pfau wrote:
 Looks very nice, some things to refine:

 "Any attributes are allowed on these methods."
 * Should  safe and  trusted by disallowed as
    " safe code may not issue explicit calls to
     opAddRef/opRelease"?
 * Probably also add a note here that the functions must be inverse
 and a note that they should be nothrow and/or final for performance.
OK. I don't want to impose many limitations - let users explore possibilities. I added the recommendation.
Leaving the implementation of opAddRef/opRelease to the user really opens some interesting possibilities. Wrapping manually reference-counted C libraries is a rather obvious one but there are probably more interesting cases. Overall this proposal looks very nice :-)
Feb 26 2015
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/26/15 3:12 PM, Johannes Pfau wrote:
 Am Thu, 26 Feb 2015 14:53:16 -0800
 schrieb Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>:

 On 2/26/15 2:39 PM, Johannes Pfau wrote:
 Looks very nice, some things to refine:

 "Any attributes are allowed on these methods."
 * Should  safe and  trusted by disallowed as
     " safe code may not issue explicit calls to
      opAddRef/opRelease"?
 * Probably also add a note here that the functions must be inverse
 and a note that they should be nothrow and/or final for performance.
OK. I don't want to impose many limitations - let users explore possibilities. I added the recommendation.
Leaving the implementation of opAddRef/opRelease to the user really opens some interesting possibilities. Wrapping manually reference-counted C libraries is a rather obvious one but there are probably more interesting cases.
Yah, this should dovetail real nice with allocators too.
 Overall this proposal looks very nice :-)
Still looking for some sword to fall :o). Andrei
Feb 26 2015
prev sibling next sibling parent reply "Brian Schott" <briancschott gmail.com> writes:
On Thursday, 26 February 2015 at 21:50:56 UTC, Andrei 
Alexandrescu wrote:
 http://wiki.dlang.org/DIP74 got to reviewable form. Please 
 destroy and discuss.

 Thanks,

 Andrei
"This is important because it limits what reference counted types." - I'm not sure what this means. "The methods may or may not be final or inherited." - Should this be "final or virtual"? "Any attributes are allowed on these methods." - I'm going to have to write a static analysis warning for marking these "const". "Call is inserted only if the reference is not null" - Should this be "Call is executed only if the reference is not null"? "</tt>opRelease</tt>" - Some markup escaped into the wild! "The same is achievable with RCOs by means of disable opAddRef();" - Suggestion: add some text stating that opRelease() must still be present and implemented. "Attention must be paid to annotate with return all functions that return references to owned data" -> "Attention must be paid to annotate all functions that return references to owned data with `return`"
Feb 26 2015
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/26/15 2:42 PM, Brian Schott wrote:
 On Thursday, 26 February 2015 at 21:50:56 UTC, Andrei Alexandrescu wrote:
 http://wiki.dlang.org/DIP74 got to reviewable form. Please destroy and
 discuss.

 Thanks,

 Andrei
"This is important because it limits what reference counted types." - I'm not sure what this means. "The methods may or may not be final or inherited." - Should this be "final or virtual"? "Any attributes are allowed on these methods." - I'm going to have to write a static analysis warning for marking these "const". "Call is inserted only if the reference is not null" - Should this be "Call is executed only if the reference is not null"? "</tt>opRelease</tt>" - Some markup escaped into the wild! "The same is achievable with RCOs by means of disable opAddRef();" - Suggestion: add some text stating that opRelease() must still be present and implemented. "Attention must be paid to annotate with return all functions that return references to owned data" -> "Attention must be paid to annotate all functions that return references to owned data with `return`"
Excellent notes, of which two important ones. Addressed - reload http://wiki.dlang.org/DIP74 - thanks! -- Andrei
Feb 26 2015
prev sibling next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

The compiler detects automatically and treats specially all 
classes and interfaces that define the following two methods:<
Defining only one of those methods needs to give a compile-time error.
This lowering assumes left-to-right evaluation of function 
parameters.<
Is this currently enforced in all D compilers?
This DIP allows defining reference counted class objects that 
are usable in  safe code. However, it does not enforce safety.<
And do you plan to later design what's needed to enforce their safety? Bye, bearophile
Feb 26 2015
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/26/15 3:19 PM, bearophile wrote:
 Andrei Alexandrescu:

 The compiler detects automatically and treats specially all classes
 and interfaces that define the following two methods:<
Defining only one of those methods needs to give a compile-time error.
Well types that define empty() and front() but not popFront() are not in error, either.
 This lowering assumes left-to-right evaluation of function parameters.<
Is this currently enforced in all D compilers?
No, though there have been improvements. Brian submitted an(other) issue.
 This DIP allows defining reference counted class objects that are
 usable in  safe code. However, it does not enforce safety.<
And do you plan to later design what's needed to enforce their safety?
Not at this time. Andrei
Feb 26 2015
prev sibling next sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Thursday, 26 February 2015 at 21:50:56 UTC, Andrei 
Alexandrescu wrote:
 http://wiki.dlang.org/DIP74 got to reviewable form. Please 
 destroy and discuss.

 Thanks,

 Andrei
"The compiler detects automatically and treats specially all classes and interfaces that define the following two methods:" Well, RefCounted could use compile time reflexion to do so. Even better, we could define a lvalue property for RefCounted to use a counter so we can do intrusive counting in both classes and structs. " safe code may not issue explicit calls to opAddRef/opRelease. " I guess we could simply make them system . " RCOs objects are subject to additional limitations compared to their GC counterparts: No conversion to Object or interfaces that are not reference counted " No problem, I'm gonna duplicate all my code and as will every single library writer out there. Missing: All write of RCO reference to statics must be atomic and ordered as long as the language can't enforce thread locality (at least in safe code). Generally: This DIP works around (announced) limitations of DIP25. As escape can only be checked properly for type with no indirections, and only solve the problem for classes/interfaces. Other type with indirection remains an unsolved problem. If I were in charge, that would be a clear no, and the sign that DIP25 approach needs to be reworked, as wack-a-mole is not a good way to handle design.
Feb 26 2015
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/26/15 4:09 PM, deadalnix wrote:
 On Thursday, 26 February 2015 at 21:50:56 UTC, Andrei Alexandrescu wrote:
 http://wiki.dlang.org/DIP74 got to reviewable form. Please destroy and
 discuss.

 Thanks,

 Andrei
"The compiler detects automatically and treats specially all classes and interfaces that define the following two methods:" Well, RefCounted could use compile time reflexion to do so. Even better, we could define a lvalue property for RefCounted to use a counter so we can do intrusive counting in both classes and structs.
No, see below how typechecking is more strict for RCOs. -- Andrei
Feb 26 2015
parent reply "deadalnix" <deadalnix gmail.com> writes:
On Friday, 27 February 2015 at 00:12:32 UTC, Andrei Alexandrescu 
wrote:
 Well, RefCounted could use compile time reflexion to do so. 
 Even better,
 we could define a lvalue property for RefCounted to use a 
 counter so we
 can do intrusive counting in both classes and structs.
No, see below how typechecking is more strict for RCOs. -- Andrei
That is simply a rhetoric way to not admit failure of DIP25 and DIP69.
Feb 26 2015
next sibling parent ketmar <ketmar ketmar.no-ip.org> writes:
On Fri, 27 Feb 2015 00:36:41 +0000, deadalnix wrote:

 On Friday, 27 February 2015 at 00:12:32 UTC, Andrei Alexandrescu wrote:
 Well, RefCounted could use compile time reflexion to do so.
 Even better,
 we could define a lvalue property for RefCounted to use a counter so
 we can do intrusive counting in both classes and structs.
No, see below how typechecking is more strict for RCOs. -- Andrei
=20 That is simply a rhetoric way to not admit failure of DIP25 and DIP69.
this stinks in the same way as DIP25 stinks. right here: "Attention must=20 be paid to annotate all functions returning references to owned data with=20 return." this single thing will bring enormous pile of bugs. i want to=20 have $1 each time someone will be hit by the bug "oh, i forgot to put=20 `return` there!", so i can drop my work and do nothing 'till the end of=20 my life.=
Feb 26 2015
prev sibling parent ketmar <ketmar ketmar.no-ip.org> writes:
ooops, sorry, deadalnix, i was meant to post this as the answer to the OP=20
post.=
Feb 26 2015
prev sibling next sibling parent reply "weaselcat" <weaselcat gmail.com> writes:
On Friday, 27 February 2015 at 00:10:00 UTC, deadalnix wrote:
 No problem, I'm gonna duplicate all my code and as will every 
 single library writer out there.
Correct me if I'm wrong, but to me this presents itself as an alternative only for things that require deterministic ownership semantics(e.g, OpenGL resource wrapper) I don't think this is a full ARC system intended to replace the GC that would require library authors to write two versions of their libraries. But I could be entirely wrong.
Feb 26 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/26/15 5:41 PM, weaselcat wrote:
 On Friday, 27 February 2015 at 00:10:00 UTC, deadalnix wrote:
 No problem, I'm gonna duplicate all my code and as will every single
 library writer out there.
Correct me if I'm wrong, but to me this presents itself as an alternative only for things that require deterministic ownership semantics(e.g, OpenGL resource wrapper) I don't think this is a full ARC system intended to replace the GC that would require library authors to write two versions of their libraries. But I could be entirely wrong.
DIP74 allows defining objects outside the Object hierarchy that are reference counted. This allows apps in which GC and RC approaches coexist. An interesting option to explore in the future would be rigging druntime to add opAddRef and opRelease to Object. Andrei
Feb 26 2015
parent reply "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Thu, Feb 26, 2015 at 05:44:36PM -0800, Andrei Alexandrescu via Digitalmars-d
wrote:
[...]
 An interesting option to explore in the future would be rigging
 druntime to add opAddRef and opRelease to Object.
[...] How would that work? Doesn't that immediately subject *all* classes to the restrictions set forth in DIP74? T -- Gone Chopin. Bach in a minuet.
Feb 26 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/26/15 5:59 PM, H. S. Teoh via Digitalmars-d wrote:
 On Thu, Feb 26, 2015 at 05:44:36PM -0800, Andrei Alexandrescu via
Digitalmars-d wrote:
 [...]
 An interesting option to explore in the future would be rigging
 druntime to add opAddRef and opRelease to Object.
[...] How would that work? Doesn't that immediately subject *all* classes to the restrictions set forth in DIP74?
It does - but that might be fine with some applications. -- Andrei
Feb 26 2015
parent reply "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Thu, Feb 26, 2015 at 06:06:04PM -0800, Andrei Alexandrescu via Digitalmars-d
wrote:
 On 2/26/15 5:59 PM, H. S. Teoh via Digitalmars-d wrote:
On Thu, Feb 26, 2015 at 05:44:36PM -0800, Andrei Alexandrescu via Digitalmars-d
wrote:
[...]
An interesting option to explore in the future would be rigging
druntime to add opAddRef and opRelease to Object.
[...] How would that work? Doesn't that immediately subject *all* classes to the restrictions set forth in DIP74?
It does - but that might be fine with some applications. -- Andrei
But putting it into druntime imposes it on *all* applications, because either opAddRef/opRelease are declared in Object, or they are not, and this decision is made long before the user writes his application. T -- In theory, software is implemented according to the design that has been carefully worked out beforehand. In practice, design documents are written after the fact to describe the sorry mess that has gone on before.
Feb 26 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/26/15 6:21 PM, H. S. Teoh via Digitalmars-d wrote:
 On Thu, Feb 26, 2015 at 06:06:04PM -0800, Andrei Alexandrescu via
Digitalmars-d wrote:
 On 2/26/15 5:59 PM, H. S. Teoh via Digitalmars-d wrote:
 On Thu, Feb 26, 2015 at 05:44:36PM -0800, Andrei Alexandrescu via
Digitalmars-d wrote:
 [...]
 An interesting option to explore in the future would be rigging
 druntime to add opAddRef and opRelease to Object.
[...] How would that work? Doesn't that immediately subject *all* classes to the restrictions set forth in DIP74?
It does - but that might be fine with some applications. -- Andrei
But putting it into druntime imposes it on *all* applications, because either opAddRef/opRelease are declared in Object, or they are not, and this decision is made long before the user writes his application.
That's why I used "rigging" - meaning "equip for special purpose". "Hacking" is clearer. Someone may decide to just add opAddRef/opRelease to Object for a system or application. Or make the addition subject to a versioning flag (and therefore have two druntime builds available). Andrei
Feb 26 2015
parent "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Thu, Feb 26, 2015 at 06:39:12PM -0800, Andrei Alexandrescu via Digitalmars-d
wrote:
 On 2/26/15 6:21 PM, H. S. Teoh via Digitalmars-d wrote:
On Thu, Feb 26, 2015 at 06:06:04PM -0800, Andrei Alexandrescu via Digitalmars-d
wrote:
On 2/26/15 5:59 PM, H. S. Teoh via Digitalmars-d wrote:
On Thu, Feb 26, 2015 at 05:44:36PM -0800, Andrei Alexandrescu via Digitalmars-d
wrote:
[...]
An interesting option to explore in the future would be rigging
druntime to add opAddRef and opRelease to Object.
[...] How would that work? Doesn't that immediately subject *all* classes to the restrictions set forth in DIP74?
It does - but that might be fine with some applications. -- Andrei
But putting it into druntime imposes it on *all* applications, because either opAddRef/opRelease are declared in Object, or they are not, and this decision is made long before the user writes his application.
That's why I used "rigging" - meaning "equip for special purpose". "Hacking" is clearer. Someone may decide to just add opAddRef/opRelease to Object for a system or application. Or make the addition subject to a versioning flag (and therefore have two druntime builds available).
[...] Ahhh, I see what you mean now. That's an interesting idea... I suppose people like Manu could like to do something like this to get ARC by default, for example. T -- Do not reason with the unreasonable; you lose by definition.
Feb 26 2015
prev sibling parent reply "anonymous" <anonymous example.com> writes:
On Friday, 27 February 2015 at 00:10:00 UTC, deadalnix wrote:
 On Thursday, 26 February 2015 at 21:50:56 UTC, Andrei 
 Alexandrescu wrote:
 http://wiki.dlang.org/DIP74 got to reviewable form. Please 
 destroy and discuss.

 Thanks,

 Andrei
"The compiler detects automatically and treats specially all classes and interfaces that define the following two methods:" Well, RefCounted could use compile time reflexion to do so. Even better, we could define a lvalue property for RefCounted to use a counter so we can do intrusive counting in both classes and structs. " safe code may not issue explicit calls to opAddRef/opRelease. " I guess we could simply make them system . " RCOs objects are subject to additional limitations compared to their GC counterparts: No conversion to Object or interfaces that are not reference counted " No problem, I'm gonna duplicate all my code and as will every single library writer out there. Missing: All write of RCO reference to statics must be atomic and ordered as long as the language can't enforce thread locality (at least in safe code). Generally: This DIP works around (announced) limitations of DIP25. As escape can only be checked properly for type with no indirections, and only solve the problem for classes/interfaces. Other type with indirection remains an unsolved problem. If I were in charge, that would be a clear no, and the sign that DIP25 approach needs to be reworked, as wack-a-mole is not a good way to handle design.
We all pray you become less of a gaping asshole before youre in charge of anything.
Feb 26 2015
next sibling parent "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Friday, 27 February 2015 at 07:44:18 UTC, anonymous wrote:
 On Friday, 27 February 2015 at 00:10:00 UTC, deadalnix wrote:
 On Thursday, 26 February 2015 at 21:50:56 UTC, Andrei 
 Alexandrescu wrote:
 http://wiki.dlang.org/DIP74 got to reviewable form. Please 
 destroy and discuss.

 Thanks,

 Andrei
"The compiler detects automatically and treats specially all classes and interfaces that define the following two methods:" Well, RefCounted could use compile time reflexion to do so. Even better, we could define a lvalue property for RefCounted to use a counter so we can do intrusive counting in both classes and structs. " safe code may not issue explicit calls to opAddRef/opRelease. " I guess we could simply make them system . " RCOs objects are subject to additional limitations compared to their GC counterparts: No conversion to Object or interfaces that are not reference counted " No problem, I'm gonna duplicate all my code and as will every single library writer out there. Missing: All write of RCO reference to statics must be atomic and ordered as long as the language can't enforce thread locality (at least in safe code). Generally: This DIP works around (announced) limitations of DIP25. As escape can only be checked properly for type with no indirections, and only solve the problem for classes/interfaces. Other type with indirection remains an unsolved problem. If I were in charge, that would be a clear no, and the sign that DIP25 approach needs to be reworked, as wack-a-mole is not a good way to handle design.
We all pray you become less of a gaping asshole before youre in charge of anything.
In fact, "we all" don't. Quite the opposite, several of the participants of these forums (me included) happen to agree with him on many things, not just this particular topic. That's because he brings forward good arguments for his opinions, which is evidently something you aren't capable of.
Feb 27 2015
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Friday, 27 February 2015 at 07:44:18 UTC, anonymous wrote:
 We all pray you become less of a gaping asshole before youre in
 charge of anything.
Thank you for the compliment :)
Feb 27 2015
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 2/26/2015 11:44 PM, anonymous wrote:
 We all pray you become less of a [...]
cut it out.
Feb 28 2015
prev sibling next sibling parent reply ketmar <ketmar ketmar.no-ip.org> writes:
On Thu, 26 Feb 2015 13:50:55 -0800, Andrei Alexandrescu wrote:

 http://wiki.dlang.org/DIP74 got to reviewable form. Please destroy and
 discuss.
=20
 Thanks,
=20
 Andrei
this stinks in the same way as DIP25 stinks. right here: "Attention must=20 be paid to annotate all functions returning references to owned data with=20 return." this single thing will bring enormous pile of bugs. i want to=20 have $1 each time someone will be hit by the bug "oh, i forgot to put=20 `return` there!", so i can drop my work and do nothing 'till the end of=20 my life.=
Feb 26 2015
parent reply "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Fri, Feb 27, 2015 at 12:59:38AM +0000, ketmar via Digitalmars-d wrote:
 On Thu, 26 Feb 2015 13:50:55 -0800, Andrei Alexandrescu wrote:
 
 http://wiki.dlang.org/DIP74 got to reviewable form. Please destroy
 and discuss.
 
 Thanks,
 
 Andrei
this stinks in the same way as DIP25 stinks. right here: "Attention must be paid to annotate all functions returning references to owned data with return." this single thing will bring enormous pile of bugs.
[...] Wait, are you saying that forgetting the 'return' annotation will still compile without any warning?? Wow, that's ... not nice. :-( T -- Those who don't understand D are condemned to reinvent it, poorly. -- Daniel N
Feb 26 2015
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/26/15 5:37 PM, H. S. Teoh via Digitalmars-d wrote:
 On Fri, Feb 27, 2015 at 12:59:38AM +0000, ketmar via Digitalmars-d wrote:
 On Thu, 26 Feb 2015 13:50:55 -0800, Andrei Alexandrescu wrote:

 http://wiki.dlang.org/DIP74 got to reviewable form. Please destroy
 and discuss.

 Thanks,

 Andrei
this stinks in the same way as DIP25 stinks. right here: "Attention must be paid to annotate all functions returning references to owned data with return." this single thing will bring enormous pile of bugs.
[...] Wait, are you saying that forgetting the 'return' annotation will still compile without any warning?? Wow, that's ... not nice. :-(
The compiler will issue errors if returning ref to direct members. There won't be errors with returning ref to owned indirect members that the class deallocates manually. -- Andrei
Feb 26 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/26/15 5:43 PM, Andrei Alexandrescu wrote:
 The compiler will issue errors if returning ref to direct members. There
 won't be errors with returning ref to owned indirect members that the
 class deallocates manually. -- Andrei
To clarify this point, which I think is important, consider: class Widget { private int x; private int[] a; ... ref int getX() { return x; } int[] getA() { return a; } } This is all fine and dandy - people can take and keep a reference to x in a GC object, and of course can get keep the array (or a portion of it) etc. Now say we port Widget to an RC system: class Widget { private int x; private int[] a; ... ref int getX() { return x; } int[] getA() { return a; } void opAddRef(); void opRelease(); } Not getX() does NOT compile anymore, whereas getA() CONTINUES to compile. To make getX() compile, the user must change code to: ref int getX() return { return x; } That makes the compiler go, "oh ok I'll make sure the reference doesn't outlive the current object". And all is again fine and dandy. Now if the person defining Widget wants to own (and release deterministically) the array, they must make sure their use of memory is scoped appropriately, e.g. by using RCSlice. Andrei
Feb 26 2015
parent "deadalnix" <deadalnix gmail.com> writes:
On Friday, 27 February 2015 at 02:05:33 UTC, Andrei Alexandrescu 
wrote:
 On 2/26/15 5:43 PM, Andrei Alexandrescu wrote:
 The compiler will issue errors if returning ref to direct 
 members. There
 won't be errors with returning ref to owned indirect members 
 that the
 class deallocates manually. -- Andrei
To clarify this point, which I think is important, consider: class Widget { private int x; private int[] a; ... ref int getX() { return x; } int[] getA() { return a; } } This is all fine and dandy - people can take and keep a reference to x in a GC object, and of course can get keep the array (or a portion of it) etc. Now say we port Widget to an RC system: class Widget { private int x; private int[] a; ... ref int getX() { return x; } int[] getA() { return a; } void opAddRef(); void opRelease(); } Not getX() does NOT compile anymore, whereas getA() CONTINUES to compile. To make getX() compile, the user must change code to: ref int getX() return { return x; } That makes the compiler go, "oh ok I'll make sure the reference doesn't outlive the current object". And all is again fine and dandy. Now if the person defining Widget wants to own (and release deterministically) the array, they must make sure their use of memory is scoped appropriately, e.g. by using RCSlice. Andrei
It is the same with a pointer to a struct.
Feb 26 2015
prev sibling next sibling parent ketmar <ketmar ketmar.no-ip.org> writes:
On Thu, 26 Feb 2015 17:37:46 -0800, H. S. Teoh via Digitalmars-d wrote:

 On Fri, Feb 27, 2015 at 12:59:38AM +0000, ketmar via Digitalmars-d
 wrote:
 On Thu, 26 Feb 2015 13:50:55 -0800, Andrei Alexandrescu wrote:
=20
 http://wiki.dlang.org/DIP74 got to reviewable form. Please destroy
 and discuss.
=20
 Thanks,
=20
 Andrei
=20 this stinks in the same way as DIP25 stinks. right here: "Attention must be paid to annotate all functions returning references to owned data with return." this single thing will bring enormous pile of bugs.
[...] =20 Wait, are you saying that forgetting the 'return' annotation will still compile without any warning?? Wow, that's ... not nice. :-(
yep. this is the case for DIP25 too (see RCArray sample: it compiles=20 perfectly fine without `return`).=
Feb 26 2015
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 2/26/2015 5:37 PM, H. S. Teoh via Digitalmars-d wrote:
 Wait, are you saying that forgetting the 'return' annotation will still
 compile without any warning?? Wow, that's ... not nice. :-(
Indeed, and the compiler will error out if you try that: --- struct S { int x; } ref int foo(ref S s) { return s.x; } --- dmd -c foo -dip25 foo.d(7): Error: escaping reference to local ref variable s There'd be no point to DIP25 if it didn't.
Feb 26 2015
parent reply "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Thu, Feb 26, 2015 at 11:35:55PM -0800, Walter Bright via Digitalmars-d wrote:
 On 2/26/2015 5:37 PM, H. S. Teoh via Digitalmars-d wrote:
Wait, are you saying that forgetting the 'return' annotation will
still compile without any warning?? Wow, that's ... not nice. :-(
Indeed, and the compiler will error out if you try that: --- struct S { int x; } ref int foo(ref S s) { return s.x; } --- dmd -c foo -dip25 foo.d(7): Error: escaping reference to local ref variable s There'd be no point to DIP25 if it didn't.
Huh? We weren't talking about that -- it's already a given that this case works, otherwise DIP25 would truly have no point. The problematic case comes from the manually-managed array member that you can freely return, yet it may become a dangling reference once opRelease deallocates it: class S { int[] data; int[] foo() { return data; } // <-- happily compiles void opAddRef() { ... } void opRelease() { ... GC.free(data); // <-- uh oh } } int[] fun() { S s = /* create instance of S */ return s.foo(); // s goes out of scope here, and opRelease() cleans up // but we now have an escaping reference to s.data } void main() { int[] dangling = fun(); dangling[0] = 1; // kaboom } S.foo() should have been annotated with 'return', but the programmer forgot and the compiler still accepts the code without any warnings, thereby violating safe. T -- Bomb technician: If I'm running, try to keep up.
Feb 27 2015
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/27/15 7:42 AM, H. S. Teoh via Digitalmars-d wrote:
 S.foo() should have been annotated with 'return', but the programmer
 forgot and the compiler still accepts the code without any warnings,
 thereby violating  safe.
That is correct. However, the user is on the hook because her use of trusted when deallocating the array. I think the right thing to do about owned data is to give it its own abstraction, and plant it in the standard library. RCSlice would be an obvious go-to structure. Could you consider defining an OwnedSlice and see how far you can get? Andrei
Feb 27 2015
parent "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Fri, Feb 27, 2015 at 08:00:20AM -0800, Andrei Alexandrescu via Digitalmars-d
wrote:
 On 2/27/15 7:42 AM, H. S. Teoh via Digitalmars-d wrote:
S.foo() should have been annotated with 'return', but the programmer
forgot and the compiler still accepts the code without any warnings,
thereby violating  safe.
That is correct. However, the user is on the hook because her use of trusted when deallocating the array.
[...] Which shows just how dangerous trusted is. :-P But that's a good point. The use of trusted in theory should have raised red flags that the programmer needs to be careful here. There's also the case of using malloc/free to allocate the array, but I suppose that falls in the same category. T -- A bend in the road is not the end of the road unless you fail to make the turn. -- Brian White
Feb 27 2015
prev sibling parent "deadalnix" <deadalnix gmail.com> writes:
Yup, it sound like the destruction should be delegated to the 
destructor.

Maybe the release method could return the refcount ?
Feb 27 2015
prev sibling next sibling parent "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
On Thu, Feb 26, 2015 at 01:50:55PM -0800, Andrei Alexandrescu via Digitalmars-d
wrote:
 http://wiki.dlang.org/DIP74 got to reviewable form. Please destroy and
 discuss.
[...] Under "Rules":
 The complexity of this code underlies the importance of making
^^^^^^^^^ Should be "underlines"
 opAddRef and especially opRelease nothrow. In that case the
 scope(failure) statement may be elided.
Under "Rules":
 struct, class, and closure types that have RCO members accommodate
 calls to Release during their destruction.
This is unclear to me. What exactly is the semantics of "accomodate calls to Release"? And what is "Release"? Did you mean opRelease? Also, the code example following is also unclear; since struct A has no RCO members that I can see, does that mean the calling sequences (labelled 1-9) apply to *all* structs now? Is Widget supposed to be RCO (this is not stated clearly)? Similarly, in the next example about fun(exprA, exprB, exprC) it's not clear exactly which parameter is supposed to be RCO. I can guess, but it's better to be 100% unambiguous. Then the rule that states that opAddRef and opRelease are not issued for 'this': is this safe from race conditions? E.g., if I'm inside a method and somebody outside calls opRelease and frees the object 'this' points to. Or are we assuming that RCOs must be thread-local? If so, this should be stated explicitly. Under "Relinquishing an owned resource":
 The method is correctly not annotated with return because the slice it
 returns is not scoped by this. Note that if the implementer of Widget
 forgets the assignment _payload = null, user code may end up with a
 dangling reference. 
So basically such a method cannot be marked safe, right? T -- Only boring people get bored. -- JM
Feb 26 2015
prev sibling next sibling parent reply Rikki Cattermole <alphaglosined gmail.com> writes:
On 27/02/2015 10:50 a.m., Andrei Alexandrescu wrote:
 http://wiki.dlang.org/DIP74 got to reviewable form. Please destroy and
 discuss.

 Thanks,

 Andrei
Either I missed something or: If I go new a type like: Widget widget = new Widget(); This would still use the GC to allocate the memory + emplace it. Even if it contains the two special RC functions. Also what about properties? What if one of them may or may not be RC'd. Should there be a conditional call to the GC to add it to be scanned on assignment? Anyway, I think it is mostly there.
Feb 26 2015
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/26/15 5:28 PM, Rikki Cattermole wrote:
 On 27/02/2015 10:50 a.m., Andrei Alexandrescu wrote:
 http://wiki.dlang.org/DIP74 got to reviewable form. Please destroy and
 discuss.

 Thanks,

 Andrei
Either I missed something or: If I go new a type like: Widget widget = new Widget(); This would still use the GC to allocate the memory + emplace it. Even if it contains the two special RC functions.
Yah, DIP74 is intentionally very "policy up, implementation down". It completely leaves the allocation mechanism to user code. See e.g. this excerpt: "Usually such approaches also use private constructors and object factories to ensure the same allocation method is used during creation and destruction of the object."
 Also what about properties?
 What if one of them may or may not be RC'd. Should there be a
 conditional call to the GC to add it to be scanned on assignment?
I don't understand this. Members compose naturally. Andrei
Feb 26 2015
prev sibling next sibling parent reply "weaselcat" <weaselcat gmail.com> writes:
On Thursday, 26 February 2015 at 21:50:56 UTC, Andrei 
Alexandrescu wrote:
 http://wiki.dlang.org/DIP74 got to reviewable form. Please 
 destroy and discuss.

 Thanks,

 Andrei
P.S., am I too late to complain about the choice of 'return' in DIP25? :) If someone who learned C(++) but had used D read this ref int opIndex(size_t n) return { // mark this as a non-escape reference return _payload[n]; } I'm not sure if they could make heads or tails of what the first return is supposed to be doing.
Feb 26 2015
parent "weaselcat" <weaselcat gmail.com> writes:
On Friday, 27 February 2015 at 02:05:12 UTC, weaselcat wrote:
 On Thursday, 26 February 2015 at 21:50:56 UTC, Andrei 
 Alexandrescu wrote:
 http://wiki.dlang.org/DIP74 got to reviewable form. Please 
 destroy and discuss.

 Thanks,

 Andrei
P.S., am I too late to complain about the choice of 'return' in DIP25? :) If someone who learned C(++) but had used D read this
hadn't*, Sorry.
Feb 26 2015
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2015-02-26 22:50, Andrei Alexandrescu wrote:
 http://wiki.dlang.org/DIP74 got to reviewable form. Please destroy and
 discuss.
* What will happen if these methods are defined on a class that is allocated on the GC? Is there any enforcement against this? Is there any way an unsafe operation can happen, i.e. the GC deleting a class that has already been destroyed by reference counting? What about enforcing a third method, "allocate" or similar. This method will do the actually allocation of a class instance. "new Foo" could be lowered to a call to "allocate". * I know this is bikeshedding but I think it's important. This is a breaking change, like it or not, and it's the worst kind. The kind that if a class exists with these methods it will continue to happily compile without errors or warnings but will have different semantic behavior. Therefore I recommend requiring a compiler recognized UDA, in one of the following ways: A. arc class Foo { T1 opAddRef(); T2 opRelease(); } If a class is marked with arc the compiler will enforce that both "opAddRef" and "opRelease" are defined with the expected signatures. B. class Foo { arc T1 opAddRef(); arc T2 opRelease(); } If either a method is called "opAddRef" or "opRelease" and it's marked with arc, the compiler will enforce that the other method is defined and marked with arc as well. The signatures of the methods are enforced as well. C. class Foo { arc("addRef") T1 foo(); arc("release") T2 bar(); } Basically the same as B but the actual methods can be called anything. Alternative A gives a clear documentation it's a reference counted class without having to scan the methods. -- /Jacob Carlborg
Feb 26 2015
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Jacob Carlborg:

  arc class Foo
 {
     T1 opAddRef();
     T2 opRelease();
 }
 ...
 Alternative A gives a clear documentation it's a reference 
 counted class without having to scan the methods.
Assuming you want something like DIP74, this design design seems safer than the design proposed in DIP74. Bye, bearophile
Mar 01 2015
parent "Taylor Hillegeist" <taylorh140 gmail.com> writes:
On Sunday, 1 March 2015 at 13:13:58 UTC, bearophile wrote:
 Jacob Carlborg:

  arc class Foo
 {
    T1 opAddRef();
    T2 opRelease();
 }
 ...
 Alternative A gives a clear documentation it's a reference 
 counted class without having to scan the methods.
Assuming you want something like DIP74, this design design seems safer than the design proposed in DIP74. Bye, bearophile
So, I don't know a huge amount about this subject. aka. (hold my beer) but I do know that seemingly by default D has garbage collection which is wonderful... but It is also wonderful to have choices. I see a story like the tortoise and the hare. Where the garbage collector is like the hare, going really fast but then taking a break. Reference counting is like the tortoise, a bit slower but more predictable. It is clear Reference counting takes more discipline, but unclear to me how D will help/guide its users through process. it seems like the safe will disallow some obviously dumb things. which is actually really awesome. It is also unclear how combining both RC and GC will work, how does the GC know not to scan the RC's territory? And if it does is it actually beneficial to have RC? As far as DIP74: In the Definition I am confused what UFCS has to do with defining the opAddRef() and opRelease() methods. And also why the are used in the fun() x.opAddref() example. I probably have like 100 more dumb questions but lets leave it there. :D
Mar 02 2015
prev sibling next sibling parent Jacob Carlborg <doob me.com> writes:
On 2015-02-26 22:50, Andrei Alexandrescu wrote:
 http://wiki.dlang.org/DIP74 got to reviewable form. Please destroy and
 discuss.
To me this looks like ARC (Automated Reference Counting). I know that Walter has several complains about ARC, like he wrote in another thread [1]: "RC has further performance and code bloat problems when used with exception handling" Is that dealt with or is it something one just have to accepted when using reference counting? [1] http://forum.dlang.org/post/mcbejn$2tao$1 digitalmars.com -- /Jacob Carlborg
Feb 26 2015
prev sibling next sibling parent reply ted <foo bar.com> writes:
Andrei Alexandrescu wrote:

 http://wiki.dlang.org/DIP74 got to reviewable form. Please destroy and
 discuss.
 
 Thanks,
 
 Andrei
Trivial typos: struct, class, and closure types that have RCO members accommodate calls to Release during their destruction. s/Release/opRelease/ Explicit casting to of from void* does not entail a call to opAddRef. s/of/or/ also: s/opReleasecalls/opRelease calls/ The examples in "Defining a reference counted object with deallocation", and "defining a type that owns resources" both define '_refs', and manipulate 'refs'. This is probably a really stupid question, but how does the 'new' work for an RCO. I assume it uses the GC memory allocation system, but must mark it as 'not for collection' (or similar), for the GC.free() call to work (as used in the examples). Probably another silly question: How would the examples work with const/immutable (using examples in howtos)? e.g. const Widget a = new Widget; auto b = a; <-- mutable method Widget.opAddRef is not callable using a const object
Feb 27 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/27/15 1:09 AM, ted wrote:
 Andrei Alexandrescu wrote:

 http://wiki.dlang.org/DIP74 got to reviewable form. Please destroy and
 discuss.

 Thanks,

 Andrei
Trivial typos: struct, class, and closure types that have RCO members accommodate calls to Release during their destruction. s/Release/opRelease/ Explicit casting to of from void* does not entail a call to opAddRef. s/of/or/ also: s/opReleasecalls/opRelease calls/ The examples in "Defining a reference counted object with deallocation", and "defining a type that owns resources" both define '_refs', and manipulate 'refs'.
Fixed, thanks!
 This is probably a really stupid question, but how does the 'new' work for
 an RCO. I assume it uses the GC memory allocation system, but must mark it
 as 'not for collection' (or similar), for the GC.free() call to work (as
 used in the examples).
DIP74 does not prescribe specific allocation techniques. They are left to the user. One nice point of the design space would be to use the GC for allocation and early deallocation, in such a way that the GC is still able to collect cycles.
 Probably another silly question: How would the examples work with
 const/immutable (using examples in howtos)?
 e.g. const Widget a = new Widget;
       auto b = a;	<-- mutable method Widget.opAddRef is not callable
 using a const object
This is tricky. I meant to discuss it; for now I planted a TODO. Andrei
Feb 27 2015
next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 2/27/15 9:09 AM, Andrei Alexandrescu wrote:
 On 2/27/15 1:09 AM, ted wrote:
 Probably another silly question: How would the examples work with
 const/immutable (using examples in howtos)?
 e.g. const Widget a = new Widget;
       auto b = a;    <-- mutable method Widget.opAddRef is not callable
 using a const object
This is tricky. I meant to discuss it; for now I planted a TODO.
Wouldn't you bless this mechanism of logical const the same way synchronized does? -Steve
Feb 27 2015
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/27/15 6:46 AM, Steven Schveighoffer wrote:
 On 2/27/15 9:09 AM, Andrei Alexandrescu wrote:
 On 2/27/15 1:09 AM, ted wrote:
 Probably another silly question: How would the examples work with
 const/immutable (using examples in howtos)?
 e.g. const Widget a = new Widget;
       auto b = a;    <-- mutable method Widget.opAddRef is not callable
 using a const object
This is tricky. I meant to discuss it; for now I planted a TODO.
Wouldn't you bless this mechanism of logical const the same way synchronized does?
Yes, it's a similar matter. -- Andrei
Feb 27 2015
prev sibling parent reply ted <foo bar.com> writes:
Andrei Alexandrescu wrote:

 On 2/27/15 1:09 AM, ted wrote:
 Andrei Alexandrescu wrote:

 http://wiki.dlang.org/DIP74 got to reviewable form. Please destroy and
 discuss.

 Thanks,

 Andrei
Trivial typos: struct, class, and closure types that have RCO members accommodate calls to Release during their destruction. s/Release/opRelease/ Explicit casting to of from void* does not entail a call to opAddRef. s/of/or/ also: s/opReleasecalls/opRelease calls/ The examples in "Defining a reference counted object with deallocation", and "defining a type that owns resources" both define '_refs', and manipulate 'refs'.
Fixed, thanks!
 This is probably a really stupid question, but how does the 'new' work
 for an RCO. I assume it uses the GC memory allocation system, but must
 mark it as 'not for collection' (or similar), for the GC.free() call to
 work (as used in the examples).
DIP74 does not prescribe specific allocation techniques. They are left to the user.
I'm still a bit confused here: the examples in DIP74 showed the freeing of memory via 'GC.free(cast(void*) this);' - so I had assumed that 'Widget a = new Widget' would be the way it was created? (and that automatically uses GC - or is this what I am missing?) I can see how a system that used (for example) malloc/calloc/free would work, I'm just querying the consistency of the examples within DIP74?
 
 One nice point of the design space would be to use the GC for allocation
 and early deallocation, in such a way that the GC is still able to
 collect cycles.
 
 Probably another silly question: How would the examples work with
 const/immutable (using examples in howtos)?
 e.g. const Widget a = new Widget;
       auto b = a;	<-- mutable method Widget.opAddRef is not callable
 using a const object
This is tricky. I meant to discuss it; for now I planted a TODO. Andrei
Feb 27 2015
next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Friday, 27 February 2015 at 22:03:06 UTC, ted wrote:
 I can see how a system that used (for example) 
 malloc/calloc/free would
 work, I'm just querying the consistency of the examples within 
 DIP74?
That is on of the 2 main problems with this DIP. The memory management of the object is linked to its memory management, which will force a ton a code duplication. The second problem is that we are coming up with a myriad of ad hoc solutions for various aspect of the same problem, with no visibility on what the whole thing is going to look like (so there is no base to compare the current road we are taking to any alternative proposal, deemed too complex).
Feb 27 2015
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/27/15 2:03 PM, ted wrote:
 I'm still a bit confused here: the examples in DIP74 showed the freeing of
 memory via 'GC.free(cast(void*) this);' - so I had assumed that
 'Widget a = new Widget' would be the way it was created? (and that
 automatically uses GC - or is this what I am missing?)
The GC allows both manual freeing and via tracing. So after allocating with new, a user may either leave it to the GC or call the destructor followed by GC.free.
 I can see how a system that used (for example) malloc/calloc/free would
 work, I'm just querying the consistency of the examples within DIP74?
GC.malloc/GC.free and malloc/free should both work. Adnrei
Feb 27 2015
parent "Orvid King" <blah38621 gmail.com> writes:
 From the perspective of someone mostly indifferent to the support 
for it:

Why does DIP74 require the references to be counted on 
assignment? Shouldn't it be defined such that reference counting 
operations only need to occur when an unbalanced or escapable 
reference is created? This would eliminate a large number of the 
required references. As long as the reference count of an object 
is the same entering a function as when it leaves the function, 
there's no need to do a bunch of twiddling in the middle.

It also appears to me that the opAddRef in the examples is 
simpler than it should be. I believe it should be doing an 
`assert(_refs)` first, to ensure a valid state entering into the 
function.

Lastly, I believe it should be opReleaseRef rather than 
opRelease, simply to be explicit on what is being released.
Feb 27 2015
prev sibling next sibling parent "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= writes:
On Thursday, 26 February 2015 at 21:50:56 UTC, Andrei 
Alexandrescu wrote:
 http://wiki.dlang.org/DIP74 got to reviewable form. Please 
 destroy and discuss.
Destroy: The scheme is too simplistic. You need to add "policy" as a template parameter to retain/release so that you can support different ownership schemes with strong typing (compile time). You also need a policy-link between the receiver and the object. The DIP needs to prove that the protocol can be used to efficiently implement the following in various configurations: - weak-references with zeroing - auto release pools - unique ownership - optional locking and transfer between threads - wrapping of foreign objects that have their own RC scheme
Feb 27 2015
prev sibling next sibling parent "Zach the Mystic" <reachzach gggmail.com> writes:
On Thursday, 26 February 2015 at 21:50:56 UTC, Andrei 
Alexandrescu wrote:
 http://wiki.dlang.org/DIP74 got to reviewable form. Please 
 destroy and discuss.

 Thanks,

 Andrei
It's kind of funny that you were looking for an edge to my safety system -- I'll admit I don't know whether it really has an edge or not (it might be too bloated, both function-signature-wise and compile-time-wise) -- but one key advantage to any sophisticated ownership system is that automated reference counting can elide calls which it knows are unnecessary. What struck me in particular about DIP74 is how the pass-by-value protocol will force many function calls to endure an opAddRef/opRelease cycle, even if they do nothing to the reference count. What really worries me is that if the caller is responsible for the opAddRef, while the callee is responsible for the opRelease, isn't the potential optimization of eliding them just being sacrificed?
Feb 27 2015
prev sibling next sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2015-02-26 21:50:55 +0000, Andrei Alexandrescu said:

 http://wiki.dlang.org/DIP74 got to reviewable form. Please destroy and discuss.
Looks good in general. Somehow I can't help but think how overloading new and delete would be useful in combination with this. You know, this feature from D1 that was deprecated for some reason (but still work fine as far as I know)? http://digitalmars.com/d/1.0/class.html#allocators class MyRCObject { new(size_t size) { return malloc(size); } delete(void* ptr) { free(ptr); } private size_t refs = 1; void opAddRef() { ++refs; } void opRelease() { if (--refs == 0) delete this; } } This way the user doesn't have to check the documentation for the correct way to allocate this class, `new` will "just work": auto obj = new MyRCObject; It's not like the user really has any choice in how to allocate the object anyway: implicit calls to `opRelease` will make sure things break if you use a different allocation method than what it expects. - - - In your example with a payload, I think it is bad style to free the payload in opRelease. I understand you can't free the payload in the destructor to account for the case the destructor is called by the GC, but that pattern won't work if you create a class derived from Widget adding another similar payload. Just saying. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Feb 27 2015
prev sibling next sibling parent reply Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 27 February 2015 at 07:50, Andrei Alexandrescu via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 http://wiki.dlang.org/DIP74 got to reviewable form. Please destroy and
 discuss.

 Thanks,

 Andrei
I'm excited for this. I'm very happy with the approach. I'm particularly happy that it is implemented as a pair of operators. This is what I've always hoped it to look like. My initial reactions are: There's no mention of const/immutable...? Surely we can have RC immutable things right? I can't see how that works here... but it's very important. I'm not clear on structs. What is the order for calls; postblit, opInc, opDec, destructor? 75% of my use cases today are thin structs that wrap C/C++ api's. There's no mention of 'scope'. I presume functions that receive scope RC arguments will have the opportunity to have opAddRef/opRelesae elided around the call? I wonder if some standard GetRefCount function should exist? Otherwise they will probably end up being named all sorts of different things. I guess I can't think of any value in a standardisation of the function otherwise though...
Feb 27 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/27/15 7:17 AM, Manu via Digitalmars-d wrote:
 There's no mention of const/immutable...? Surely we can have RC
 immutable things right? I can't see how that works here... but it's
 very important.
Yah. I've added a TODO.
 I'm not clear on structs. What is the order for calls; postblit,
 opInc, opDec, destructor? 75% of my use cases today are thin structs
 that wrap C/C++ api's.
Structs don't get any special treatment with DIP74, only classes and interfaces.
 There's no mention of 'scope'. I presume functions that receive scope
 RC arguments will have the opportunity to have opAddRef/opRelesae
 elided around the call?
That might be a future improvement. In fact that may be possible today; I've spoken to an ARC expert who read DIP74 and said Apple's ARC does not insert a retain() for a function call, i.e. it assumes functions only borrow unless they actually do keep a pointer (e.g. assign to a member or global), and only in that case inserts a retain(). If I'm not missing something, we can do this with DIP74 which will reduce the opAddRef/opRelease traffic quite a bit.
 I wonder if some standard GetRefCount function should exist? Otherwise
 they will probably end up being named all sorts of different things. I
 guess I can't think of any value in a standardisation of the function
 otherwise though...
Yah, leave that to users. Andrei
Feb 27 2015
parent reply Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 28 February 2015 at 01:43, Andrei Alexandrescu via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On 2/27/15 7:17 AM, Manu via Digitalmars-d wrote:
 I'm not clear on structs. What is the order for calls; postblit,
 opInc, opDec, destructor? 75% of my use cases today are thin structs
 that wrap C/C++ api's.
Structs don't get any special treatment with DIP74, only classes and interfaces.
Well this is the case of the highest value to me, and DIP74 offers nothing? Can I call opAddRef/opRelease from within the postblit/destructor manually and expect the compiler to elide calls correctly? That doesn't seem foolproof though, and you also said manual calls are not safe. Why not specify a call sequence?
 There's no mention of 'scope'. I presume functions that receive scope
 RC arguments will have the opportunity to have opAddRef/opRelesae
 elided around the call?
That might be a future improvement. In fact that may be possible today; I've spoken to an ARC expert who read DIP74 and said Apple's ARC does not insert a retain() for a function call, i.e. it assumes functions only borrow unless they actually do keep a pointer (e.g. assign to a member or global), and only in that case inserts a retain(). If I'm not missing something, we can do this with DIP74 which will reduce the opAddRef/opRelease traffic quite a bit.
Hmmm, that does sound right. Very nice.
Feb 27 2015
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/27/15 7:52 AM, Manu via Digitalmars-d wrote:
 Well this is the case of the highest value to me, and DIP74 offers nothing?
For structs you use postblit and destructors. -- Andrei
Feb 27 2015
parent reply Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 28 February 2015 at 02:00, Andrei Alexandrescu via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On 2/27/15 7:52 AM, Manu via Digitalmars-d wrote:
 Well this is the case of the highest value to me, and DIP74 offers
 nothing?
For structs you use postblit and destructors. -- Andrei
That doesn't work now, and I don't see why that would suddenly work under DIP74?
Feb 28 2015
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/28/15 5:43 PM, Manu via Digitalmars-d wrote:
 On 28 February 2015 at 02:00, Andrei Alexandrescu via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 On 2/27/15 7:52 AM, Manu via Digitalmars-d wrote:
 Well this is the case of the highest value to me, and DIP74 offers
 nothing?
For structs you use postblit and destructors. -- Andrei
That doesn't work now, and I don't see why that would suddenly work under DIP74?
Per DIP25 and RCSlice, you may define a safe struct with reference counting that owns resources. -- Andrei
Feb 28 2015
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/27/15 7:52 AM, Manu via Digitalmars-d wrote:
 Can I call opAddRef/opRelease from within the postblit/destructor
 manually and expect the compiler to elide calls correctly?
 That doesn't seem foolproof though, and you also said manual calls are
 not  safe. Why not specify a call sequence?
Ah, I think you mean structs that have a class member? The compiler will insert opAddRef and opRelease appropriately: ========= * struct, class, and closure types that have RCO members accommodate calls to opRelease during their destruction. ========= Andrei
Feb 27 2015
parent reply Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 28 February 2015 at 02:02, Andrei Alexandrescu via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On 2/27/15 7:52 AM, Manu via Digitalmars-d wrote:
 Can I call opAddRef/opRelease from within the postblit/destructor
 manually and expect the compiler to elide calls correctly?
 That doesn't seem foolproof though, and you also said manual calls are
 not  safe. Why not specify a call sequence?
Ah, I think you mean structs that have a class member? The compiler will insert opAddRef and opRelease appropriately:
Well, not specifically. I mean any struct that has any indirect member(/s). The point of a struct is that the layout is entirely at user discretion, and I may want to pass some small RC aggregate by value. I'd like to see a struct with RC operators have implicit calls generated (and elided) for exactly the same set of cases as classes, in terms of construction/destruction/assignment/passing to/from functions. It's at my discretion what the contents of my struct is (in most of my cases, just pointers to opaque types, but not classes). If that's not practical (for instance, because classes assign by reference, but struc opAssign may do anything), then we should be able to call inc/dec ref manually, and have them optimise correctly? But that sounds like much more trouble to me.
 =========
 * struct, class, and closure types that have RCO members accommodate calls
 to opRelease during their destruction.
 =========


 Andrei
Feb 28 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/28/15 5:43 PM, Manu via Digitalmars-d wrote:
 I'd like to see a struct with RC operators have implicit calls
 generated (and elided) for exactly the same set of cases as classes,
 in terms of construction/destruction/assignment/passing to/from
 functions.
The short answer is that probably won't happen. -- Andrei
Feb 28 2015
parent reply Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 1 March 2015 at 12:21, Andrei Alexandrescu via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On 2/28/15 5:43 PM, Manu via Digitalmars-d wrote:
 I'd like to see a struct with RC operators have implicit calls
 generated (and elided) for exactly the same set of cases as classes,
 in terms of construction/destruction/assignment/passing to/from
 functions.
The short answer is that probably won't happen. -- Andrei
*sigh* ... ever, or in DIP74? I presented my 80% case to you before. I just want this to work efficiently: extern(C) void inc(void*); extern(C) void dec(void*); struct X { void *thing; opInc() { inc(thing); } opDec() { dec(thing); } } X is a struct, not a class. If DIP74 can't do this efficiently, then it's no use to me. Do I need to abuse the type system by declaring: class Opaque { void opInc() { inc(cast(void*)this); } void opDec() { dec(cast(void*)this); } } That's a really lame thing to do. Debuggers will dereference Y, try and present a vtable and stuff to me. In the event I want to mirror the opaque C struct definition on the D side, I can't express it because class has implicit members which aren't actually there. What is the resistance to making it work on struct? It just seems like another arbitrary edge case in the language.
Feb 28 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/28/15 6:49 PM, Manu via Digitalmars-d wrote:
 On 1 March 2015 at 12:21, Andrei Alexandrescu via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 On 2/28/15 5:43 PM, Manu via Digitalmars-d wrote:
 I'd like to see a struct with RC operators have implicit calls
 generated (and elided) for exactly the same set of cases as classes,
 in terms of construction/destruction/assignment/passing to/from
 functions.
The short answer is that probably won't happen. -- Andrei
*sigh* ... ever, or in DIP74?
In the foreseeable future.
 I presented my 80% case to you before. I just want this to work efficiently:

 extern(C) void inc(void*);
 extern(C) void dec(void*);

 struct X
 {
    void *thing;

    opInc() { inc(thing); }
    opDec() { dec(thing); }
 }
struct X { void *thing; this(this) { inc(thing); } ~this() { dec(thing); } } Andrei
Feb 28 2015
parent reply Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 1 March 2015 at 12:51, Andrei Alexandrescu via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On 2/28/15 6:49 PM, Manu via Digitalmars-d wrote:
 On 1 March 2015 at 12:21, Andrei Alexandrescu via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 On 2/28/15 5:43 PM, Manu via Digitalmars-d wrote:
 I'd like to see a struct with RC operators have implicit calls
 generated (and elided) for exactly the same set of cases as classes,
 in terms of construction/destruction/assignment/passing to/from
 functions.
The short answer is that probably won't happen. -- Andrei
*sigh* ... ever, or in DIP74?
In the foreseeable future.
 I presented my 80% case to you before. I just want this to work
 efficiently:

 extern(C) void inc(void*);
 extern(C) void dec(void*);

 struct X
 {
    void *thing;

    opInc() { inc(thing); }
    opDec() { dec(thing); }
 }
struct X { void *thing; this(this) { inc(thing); } ~this() { dec(thing); } }
You've conveniently ignored the word 'efficient'. Okay, so if I'm not better off then I've always been, what is the good of DIP74 to me?
Feb 28 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/28/15 7:01 PM, Manu via Digitalmars-d wrote:
 On 1 March 2015 at 12:51, Andrei Alexandrescu via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 On 2/28/15 6:49 PM, Manu via Digitalmars-d wrote:
 On 1 March 2015 at 12:21, Andrei Alexandrescu via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 On 2/28/15 5:43 PM, Manu via Digitalmars-d wrote:
 I'd like to see a struct with RC operators have implicit calls
 generated (and elided) for exactly the same set of cases as classes,
 in terms of construction/destruction/assignment/passing to/from
 functions.
The short answer is that probably won't happen. -- Andrei
*sigh* ... ever, or in DIP74?
In the foreseeable future.
 I presented my 80% case to you before. I just want this to work
 efficiently:

 extern(C) void inc(void*);
 extern(C) void dec(void*);

 struct X
 {
     void *thing;

     opInc() { inc(thing); }
     opDec() { dec(thing); }
 }
struct X { void *thing; this(this) { inc(thing); } ~this() { dec(thing); } }
You've conveniently ignored the word 'efficient'.
Inserting calls to opAddRef and opRelease, and the rules that allow their elision, follow quite closely (albeit not 100% identically) the rules for inserting calls to copy constructors and destructors.
 Okay, so if I'm not better off then I've always been, what is the good
 of DIP74 to me?
The title reads "Reference Counted Class Objects". Andrei
Feb 28 2015
parent reply Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 1 March 2015 at 13:13, Andrei Alexandrescu via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On 2/28/15 7:01 PM, Manu via Digitalmars-d wrote:
 On 1 March 2015 at 12:51, Andrei Alexandrescu via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 On 2/28/15 6:49 PM, Manu via Digitalmars-d wrote:
 On 1 March 2015 at 12:21, Andrei Alexandrescu via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 On 2/28/15 5:43 PM, Manu via Digitalmars-d wrote:
 I'd like to see a struct with RC operators have implicit calls
 generated (and elided) for exactly the same set of cases as classes,
 in terms of construction/destruction/assignment/passing to/from
 functions.
The short answer is that probably won't happen. -- Andrei
*sigh* ... ever, or in DIP74?
In the foreseeable future.
 I presented my 80% case to you before. I just want this to work
 efficiently:

 extern(C) void inc(void*);
 extern(C) void dec(void*);

 struct X
 {
     void *thing;

     opInc() { inc(thing); }
     opDec() { dec(thing); }
 }
struct X { void *thing; this(this) { inc(thing); } ~this() { dec(thing); } }
You've conveniently ignored the word 'efficient'.
Inserting calls to opAddRef and opRelease, and the rules that allow their elision, follow quite closely (albeit not 100% identically) the rules for inserting calls to copy constructors and destructors.
The most important case to be elided is the function call case. Passing struct to function results in postblit and destructor for every call. If postblit and destructor were sufficient, we would have been satisfied with RC in D for years.
 Okay, so if I'm not better off then I've always been, what is the good
 of DIP74 to me?
The title reads "Reference Counted Class Objects".
That title is not immutable. If DIP74 is a starting point, and you can see extension to the struct case in the future, then I'll let this go now.
Feb 28 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/28/15 7:30 PM, Manu via Digitalmars-d wrote:
 On 1 March 2015 at 13:13, Andrei Alexandrescu via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 Inserting calls to opAddRef and opRelease, and the rules that allow their
 elision, follow quite closely (albeit not 100% identically) the rules for
 inserting calls to copy constructors and destructors.
The most important case to be elided is the function call case. Passing struct to function results in postblit and destructor for every call. If postblit and destructor were sufficient, we would have been satisfied with RC in D for years.
RefCounted has been in there for quite a while and worked with structs. Its main problem was it wasn't safe. With DIP25 safety of structs (including those that use reference counting for their payload) becomes a reality.
 Okay, so if I'm not better off then I've always been, what is the good
 of DIP74 to me?
The title reads "Reference Counted Class Objects".
That title is not immutable. If DIP74 is a starting point, and you can see extension to the struct case in the future, then I'll let this go now.
It would be mightily confusing to add opAddRef and opRelease calls for structs that follow the constructors/destructors ever so closely. It might be more productive to look into improvements of optimizations related to copying objects. Andrei
Feb 28 2015
parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Sunday, 1 March 2015 at 03:43:24 UTC, Andrei Alexandrescu 
wrote:
 It might be more productive to look into improvements of 
 optimizations related to copying objects.


 Andrei
Yes please. I'd be very interested in hearing any thoughts you have on this.
Mar 01 2015
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/1/15 6:55 AM, John Colvin wrote:
 On Sunday, 1 March 2015 at 03:43:24 UTC, Andrei Alexandrescu wrote:
 It might be more productive to look into improvements of optimizations
 related to copying objects.


 Andrei
Yes please. I'd be very interested in hearing any thoughts you have on this.
One that comes to mind is: if (a) a copy b of a struct object a is created, (b) b is used only with non-mutating operations, and (c) a is not changed before b goes out of scope, then a can be directly substituted for b (no actual copy is made). Example: struct S { this(this); ~this(); int method() const; } int fun() { S a; S b = a; return b.method(); } may be lowered to: int fun() { S a; return a.method(); } Andrei
Mar 01 2015
prev sibling next sibling parent "ponce" <contact gam3sfrommars.fr> writes:
On Thursday, 26 February 2015 at 21:50:56 UTC, Andrei 
Alexandrescu wrote:
 http://wiki.dlang.org/DIP74 got to reviewable form. Please 
 destroy and discuss.

 Thanks,

 Andrei
LGTM, it is great to see something done for deterministic class destruction. It's unclear to me if an RCO object is a subtype of the corresponding class or the reverse or none.
Feb 27 2015
prev sibling next sibling parent "Volodymyr" <iackhtak gmail.com> writes:
On Thursday, 26 February 2015 at 21:50:56 UTC, Andrei
Alexandrescu wrote:
 http://wiki.dlang.org/DIP74 got to reviewable form. Please 
 destroy and discuss.

 Thanks,

 Andrei
opAddRef/opRelease breaks SOLID's single responsibility principle.
Mar 02 2015
prev sibling next sibling parent reply "Volodymyr" <iackhtak gmail.com> writes:
On Thursday, 26 February 2015 at 21:50:56 UTC, Andrei 
Alexandrescu wrote:
 http://wiki.dlang.org/DIP74 got to reviewable form. Please 
 destroy and discuss.

 Thanks,

 Andrei
With opAddRef/opRelease class does respondible for its dealocation and its own payload so breaks SOLID's single responsibility principle. As for me better design will be to do it closer to C++'s shared_ptr. e.g: // maybe with arc struct RefCounter(T) { void opAddRef(); void opRelease(); ref T obj; ref size_t count; } } RefCounter!Widged myRefToWidget; RefCounter with default ctor/dtor. opAddRef and opRelease is for compiler optimtimisation and elimination of redunadant ref counter increment/decrement.
Mar 03 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/3/15 12:53 AM, Volodymyr wrote:
 On Thursday, 26 February 2015 at 21:50:56 UTC, Andrei Alexandrescu wrote:
 http://wiki.dlang.org/DIP74 got to reviewable form. Please destroy and
 discuss.

 Thanks,

 Andrei
With opAddRef/opRelease class does respondible for its dealocation and its own payload so breaks SOLID's single responsibility principle.
Correct. That's a tactical matter that can be addressed e.g. with mixin templates.
 As
 for me better design will be to do it closer to C++'s shared_ptr.
 e.g:

 // maybe with  arc
 struct RefCounter(T)
 {
 void opAddRef();
 void opRelease();
 ref T obj;
 ref size_t count;
 }
 }

 RefCounter!Widged myRefToWidget;

 RefCounter with default ctor/dtor. opAddRef and opRelease is for
 compiler optimtimisation and elimination of redunadant ref counter
 increment/decrement.
We couldn't make that work with safety. Andrei
Mar 03 2015
parent "Volodymyr" <iackhtak gmail.com> writes:
On Tuesday, 3 March 2015 at 09:58:12 UTC, Andrei Alexandrescu 
wrote:
 On 3/3/15 12:53 AM, Volodymyr wrote:
 On Thursday, 26 February 2015 at 21:50:56 UTC, Andrei 
 Alexandrescu wrote:
 http://wiki.dlang.org/DIP74 got to reviewable form. Please 
 destroy and
 discuss.

 Thanks,

 Andrei
With opAddRef/opRelease class does respondible for its dealocation and its own payload so breaks SOLID's single responsibility principle.
Correct. That's a tactical matter that can be addressed e.g. with mixin templates.
 As
 for me better design will be to do it closer to C++'s 
 shared_ptr.
 e.g:

 // maybe with  arc
 struct RefCounter(T)
 {
 void opAddRef();
 void opRelease();
 ref T obj;
 ref size_t count;
 }
 }

 RefCounter!Widged myRefToWidget;

 RefCounter with default ctor/dtor. opAddRef and opRelease is 
 for
 compiler optimtimisation and elimination of redunadant ref 
 counter
 increment/decrement.
We couldn't make that work with safety. Andrei
Why couldn't? Let's for all return (this) functions make wrappers that rerturn RefCounter!MemberType(member, ownerCounterPtr), and same thing for public fields The wrapper nedded only for realy owned resources (but not simple gc's refs).
Mar 04 2015
prev sibling parent reply "Volodymyr" <iackhtak gmail.com> writes:
Implicit conversion to supertypes (class or interface) is allowed
ONLY if the supertype is also a reference counted type. It
follows that reference counted types cannot be converted to
Object (unless Object itself defines the two methods).

But how about calling methods of supertypes?

class Basic
{
Basic castToBasic() return
{
      return this;
}

}

class RCWidged : Basic
{
void opAddRef();
void opRelease();
// etc
}

Object a;
{
auto b = RCWidget;
a = b.castToBasic; // unsafe? opAddReff?
// b.opRelease?
}

a < new RCWidget // call to Object.opCmp. Error?

The problem with shared_ptr-like solution - "this" parameter is
not shared_ptr. You try to build shared_ptr into "this". But
basic class knows nothing about RC in child class. And those who
use the basic class know nothing.

RefCounter is unsafe and mutable. Let's do it universal (for
classes/value structs/ and unions), add method
auto opShareResource(T)(ref T t)
to handle parts of RC class that go away.

auto opShareResource(T)(ref T t)
{
      return RefCounter!T(t, ownerRefCounter);
}

this method will be called for direct or indirect access to
fields of RCClass and may wrap resource or throw or do anything
else.
Mar 04 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/4/15 5:08 AM, Volodymyr wrote:
 Implicit conversion to supertypes (class or interface) is allowed
 ONLY if the supertype is also a reference counted type. It
 follows that reference counted types cannot be converted to
 Object (unless Object itself defines the two methods).

 But how about calling methods of supertypes?
That also entails an implicit conversion. To clarify, I added this to http://wiki.dlang.org/DIP74#General: "Method calls to supertypes are only allowed if the supertype that defines the method is also reference counted." Andrei
Mar 04 2015
parent reply "bitwise" <bitwise.pvt gmail.com> writes:
After looking at DIP74, it seems that there is no way to create a 
weak reference to a ref counted object, but is not explicitly 
stated. Has this idea been considered at all?
Mar 04 2015
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/4/15 10:48 AM, bitwise wrote:
 After looking at DIP74, it seems that there is no way to create a weak
 reference to a ref counted object, but is not explicitly stated. Has
 this idea been considered at all?
DIP74 aims at not disallowing weak references whilst leaving it to libraries to effect implementations, but we'd need a proof of concept implementation to make sure DIP74 is enough as is. -- Andrei
Mar 04 2015
parent reply "bitwise" <bitwise.pvt gmail.com> writes:
On Wednesday, 4 March 2015 at 18:59:54 UTC, Andrei Alexandrescu 
wrote:
 On 3/4/15 10:48 AM, bitwise wrote:
 After looking at DIP74, it seems that there is no way to 
 create a weak
 reference to a ref counted object, but is not explicitly 
 stated. Has
 this idea been considered at all?
DIP74 aims at not disallowing weak references whilst leaving it to libraries to effect implementations, but we'd need a proof of concept implementation to make sure DIP74 is enough as is. -- Andrei
I suppose you could add "getWeak()" and "releaseWeak()" to a ref counted class, and implement a "struct Weak(T)" that calls them for you, but I doesn't seem like much of a leap to just add something like this to the DIP. couldn't "opAddWeak" and "opReleaseWeak" be added and follow identical rules to "opAddRef" and "opRelease"? The compiler could simply insert "opAddWeak() instead of opAddRef() when it found the "weak" keyword. For example: class Widget { private uint _refs = 1; private uint _weaks = 0; private int[] _payload; // owned void opAddRef() { ++_refs; } void opRelease() { if (--_refs == 0) { GC.free(_payload.ptr); _payload = null; // I'm assuming this would leave "_weaks" and "_refs" untouched this.destroy(); if(_weaks == 0) { GC.free(cast(void*)this); } } } void opAddWeak() { ++_weaks; } void opReleaseWeak() { if(--_weaks == 0 && _refs == 0) { GC.free(cast(void*)this); } } // optional/recommended bool expired() { return _refs == 0; } } Widget a = new Widget; // refs == 1, weaks == 0 Widget b = weak a; // refs == 1, weaks == 1 //a.opAddWeak(); Widget c = b; // b.opAddRef(); // refs == 2, weaks == 1 a = null; // refs == 1, weaks == 1 //a.opRelease(); assert(b.expired() == false); c = null; // refs == 0, weaks == 1 // c.opRelease(); assert(b.expired() == true); b = null; // refs == 0, weaks == 0 // b.opReleaseWeak(); ////////// or for function calls: void func(weak Widget a) { //... } Widget a = new Widget; func(a);
Mar 04 2015
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/4/15 12:04 PM, bitwise wrote:
 I suppose you could add "getWeak()" and "releaseWeak()" to a ref counted
 class
My initial attempt would be to see if opAddRef and opRelease defined by a distinct weak pointer type would work. -- Andrei
Mar 04 2015