[Dlang-study] [lifetime] Initial thoughts on lifetime management

Michel Fortin michel.fortin at michelf.ca
Wed Oct 28 12:47:30 PDT 2015


Le 28 oct. 2015 à 14:27, Andrei Alexandrescu <andrei at erdani.com> a écrit :

> Nice notation. There is an amendment I'd need to add (I think I mentioned this already): at least in v1.0 we're considering having the callER do the increment and the callEE do the decrement. This is how D currently handles copy construction and destruction, and it turns out it has a number of advantages over C++ (where the caller does all the work).
> 
> So, the protocol in foo(getObject()) is, foo's caller gets an rvalue with the already-incremented refcount and bitblits it into the call to foo, no additional operation. The code generated by foo includes the refcount decrement.
> 
> This will make for a simple implementation for v1.0 (uses the same backend as the ctors/dtors), but we need to figure whether that is the optimal approach for manipulating refcounts.

It's always a tradeoff. What you are describing is a system where the callee "consumes" its argument. With Clang, you can get that behaviour by applying "__attribute((ns_consumed))" to a function parameter.
http://clang.llvm.org/docs/AutomaticReferenceCounting.html#consumed-parameters

A good case for the "consuming" behaviour is when you chain functions:
	
	O o = transformObject(getObject());

A bad case for the "consuming" convention is calling repeatedly a function with the same object parameter. It will require at a minimum one increment and one decrement for each call:

	int a = obj{+1}.evaluate(1); // callee does this{-1}
	int b = obj{+1}.evaluate(2); // callee does this{-1}
	int c = obj{+1}.evaluate(3); // callee does this{-1}

At best you could optimize like this:

	obj{+3};
	int a = obj.evaluate(1); // callee does this{-1}
	int b = obj.evaluate(2); // callee does this{-1}
	int c = obj.evaluate(3); // callee does this{-1}

Whereas if the function is non-consuming, you get this:

	int a = obj{+1}{-1}.evaluate(1);
	int b = obj{+1}{-1}.evaluate(2);
	int c = obj{+1}{-1}.evaluate(3);

Which can be simplified as this:

	obj{+1};
	int a = obj.evaluate(1);
	int b = obj.evaluate(2);
	int c = obj.evaluate(3);
	obj{-1};

... and still has room for further elision if the context allows.

Note that you can use a mix of both. Either with an explicit attribute for arguments like the one in Clang, or by having the compiler pick one or the other by recognizing some deterministic patterns in the function signature.

Supporting both also makes it possible to integrate with COM and most RC systems out there. Usually COM is non-consuming, but not always. See CoGetInterfaceAndReleaseStream:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms691421(v=vs.85).aspx

-- 
Michel Fortin
michel.fortin at michelf.ca
https://michelf.ca




More information about the Dlang-study mailing list