July 10, 2014
On Thursday, 10 July 2014 at 20:13:18 UTC, Marc Schütz wrote:
> On Thursday, 10 July 2014 at 20:10:38 UTC, Marc Schütz wrote:
>> snip
>
> That's curious. I actually replied to H. S. Teoh in his new thread, but somehow it ended up here...

You are in the new thread...
July 10, 2014
On 7/10/2014 11:53 AM, Timon Gehr wrote:
> Are you talking about the concept, the examples, or just the last example? What
> makes it seem complicated?

I can't imagine users going to the bother of typing all that, let alone what happens when they do it wrong. Most users don't really have a good handle on what the lifetimes of their data are, so how are they going to annotate it correctly?
July 10, 2014
On Thu, Jul 10, 2014 at 11:39:57AM -0700, Andrei Alexandrescu via Digitalmars-d wrote: [...]
> We discussed this with Bartosz literally for weeks (him being a fan of auto_ptr for too long, later completely converted against it and I take credit for that :o)). With auto_ptr this was possible:
> 
> auto_ptr<int> a(new int);
> auto_ptr<int> b = a;
> 
> It would nullify a with copy syntax. That code won't compile with unique_ptr; you'd need an explicit move(a).
> 
> It only got worse from there: passing into functions, member variables...

Yep, if you pass auto_ptr into a function, it goes poof after the function returns; the original reference is gone.


> MOVING WITH COPY SYNTAX DOES NOT WORK.
> 
> It's cut and dried.
[...]

I independently invented my own version of auto_ptr many years ago, before auto_ptr got into the standard. Basically, the idea was to annotate pointers into two classes: "owner" (i.e., auto_ptr) and "reference" (i.e., "regular" pointer). Ownership is unique, so passing owner pointers has destructive copy semantics (it "transfers ownership" to the callee), whereas passing reference pointers simply makes a copy. The rule was that copying only works one way: you can only copy an owner pointer into a reference pointer, but never the other way around.

The thought was that somebody keeps a master reference to an object, assuming ownership over it, whereas others may keep as many references to it as they want, but they cannot perform owner-specific operations (like free()). Ownership may be transferred to those who are prepared to assume the responsibility of managing the object; such transfers involve destructive copy (the original owner no longer holds the rights to the object, so to speak) -- though non-owner references to that object remain valid.

Thus, passing an owner pointer into a function that expects a reference pointer simply makes a copy out of it (non-destructive), whereas passing a reference pointer where an owner is expected is illegal. (Though, of course, at the time I didn't have the means to actually enforce this, so it was merely a convention.)

With this annotation, function signatures became more self-documenting:

	class Object { ... }

	// Argument is a reference pointer; function doesn't expect
	// ownership transfer.
	int computeValue(ref Object *obj);

	// Argument is an owner pointer; i.e., the pointer is invalid
	// after the function returns. The function will assume
	// ownership of the pointer and call free(), etc., when it's
	// done.
	void addToCache(owner Object *obj);

	int main(int argc, char *argv[]) {
		owner Object *obj = new Object; // new returns an owner pointer
		ref Object *ref = obj; // OK, makes a copy of the pointer

		obj = ref; // ILLEGAL: cannot assign owner to ref

		int x = computeValue(ref); // OK, function expects ref
		x = computeValue(obj); // OK, owner implicitly converts to ref

		addToCache(ref); // ILLEGAL: ref doesn't convert to owner

		addToCache(obj); // OK: transfers ownership of obj to function
		// N.B. from here on, obj is now invalid, and any
		// dereference is a bug until it's assigned a fresh
		// owner pointer.

		obj = new Object; // OK, create another object
		free(ref);	// ILLEGAL: can only free owner pointers
		free(obj);	// OK, transfers ownership to free
		// From here on, obj is again invalid, and any further
		// dereference is a bug.

		owner Object *obj2 = new Object;
		obj = obj2; // OK, transfers ownership to obj.
		// Now obj2 is invalid and should not be dereferenced.
	}

One thing that my system didn't address, though, was the problem of dangling reference pointers after the corresponding owner pointers have been freed. That remains an unsolved problem within that system, and ultimately, requires some form of GC to adequately address.

Destructive copy, however, is tricky business; if one is not careful, one easily ends up with invalid owner pointers in the wrong places, so I agree with the sentiment of '=' being poor notation for destructive copy. Having owner pointers implicitly convert to ref pointers, however, mostly mitigates the problem -- for the most part, pointer assignments do not involve transfer of ownership, so the usual (ref) pointer semantics with non-destructive copy apply. When manipulating owner pointers, you have to be extremely careful to begin with, so generally you'd pay more attention to how it's done -- and hopefully catch problematic assignments of owner pointers.


T

-- 
Without outlines, life would be pointless.
July 10, 2014
On 07/10/2014 10:31 PM, Walter Bright via Digitalmars-d wrote:
> On 7/10/2014 12:57 PM, Robert Schadek via Digitalmars-d wrote:
>> I know this is a bit OT and personal, but could somebody please merge indexOfNeither aka indexOfNone. I just hate to copy this function from one personal project to the next.
>
> I don't know the PR link nor do I know what pseudonym you use on github, so please help!
https://github.com/D-Programming-Language/phobos/pull/1977 indexOfNeither https://github.com/D-Programming-Language/phobos/pull/2072 getoptX
>
> I reiterate my complaint that people use "virtual functions" for their github handles. There's no reason to. Who knows that 9il is actually Ilya Yaroshenko? Took me 3 virtual function dispatches to find that out!
>
burner
> Take a look at the contributor list:
>
> https://github.com/D-Programming-Language/phobos/pulls
>
> I'm sure y'all know your own handles, but how many of the others do you know who they are?
I'm starting to know faces to the usernames, but yes it is not optimal

July 10, 2014
Walter Bright:

> I can't imagine users going to the bother of typing all that, let alone what happens when they do it wrong. Most users don't really have a good handle on what the lifetimes of their data are, so how are they going to annotate it correctly?

I suggest you to go in the Rust mailing list and ask this question again.

Bye,
bearophile
July 10, 2014
On Thursday, 10 July 2014 at 18:18:54 UTC, Walter Bright wrote:
>> You are totally missing the point if you consider this even comparable
>> replacement. Reason why non-nullable types are awesome because you are 100% sure
>> compiler will force you to handle null cases and if program compiles it is
>> guaranteed to be safe in that regard. What you propose makes hardly any difference.
>
> I'll risk annoying everyone by repeating at this point "what do you propose". Making non-null pointers the default is going to break every D program and so is not acceptable.

Unfortunately I can only propose to do nothing and abandon this idea for any foreseeable future. It is one of sinkholes which consume lot of discussion time but all good solutions are unacceptable and all acceptable solutions are not practical.

One possible compromise is to define a DScanner rule to assume all normal pointers/references non-nullable by convention and enforce it for Phobos . Don't know how realistic it can be though, most likely not at all.
July 10, 2014
On Thursday, 10 July 2014 at 20:41:55 UTC, Walter Bright wrote:
> On 7/10/2014 11:53 AM, Timon Gehr wrote:
>> Are you talking about the concept, the examples, or just the last example? What
>> makes it seem complicated?
>
> I can't imagine users going to the bother of typing all that, let alone what happens when they do it wrong. Most users don't really have a good handle on what the lifetimes of their data are, so how are they going to annotate it correctly?

It doesn't need to be specified manually everywhere:

* For templates, it can be inferred.

* Local variables are either the objects _to which_ references are borrowed, in which case no annotation is necessary, or the contain returned values from functions, in which case `auto` can be used.

* Even most methods and library functions can just mark their parameters as `scope` (or whatever the syntax will be), without any mentioning of a lifetime or owner.

That leaves relatively few cases where either a reference to a passed-in parameter is returned (e.g. typical haystack-needle operations), or (more unusual), a passed in value is being kept around temporarily, e.g. as a member of a struct.

This could be reduced even more for pure functions, where the compiler can automatically allow borrowing if it's clear from the parameter and return types that no reference to the argument can be escaped.
July 10, 2014
On Thursday, 10 July 2014 at 20:57:09 UTC, Marc Schütz wrote:
> * Even most methods and library functions can just mark their parameters as `scope` (or whatever the syntax will be), without any mentioning of a lifetime or owner.


And the fact that `in` is defined as `const scope` fits nicely here.

July 10, 2014
On Thursday, 10 July 2014 at 20:39:45 UTC, John Colvin wrote:
> On Thursday, 10 July 2014 at 20:13:18 UTC, Marc Schütz wrote:
>> On Thursday, 10 July 2014 at 20:10:38 UTC, Marc Schütz wrote:
>>> snip
>>
>> That's curious. I actually replied to H. S. Teoh in his new thread, but somehow it ended up here...
>
> You are in the new thread...

Not in the forum, unfortunately:

http://forum.dlang.org/group/digitalmars.D

The two threads named "Proposal for design of 'scope'" have no replies, and my post appears in the original thread:

http://forum.dlang.org/thread/lphnen$1ml7$1@digitalmars.com?page=16#post-dvtohzrxoyzhhegzkfqf:40forum.dlang.org
July 10, 2014
On 07/10/2014 10:10 PM, "Marc Schütz" <schuetzm@gmx.net>" wrote:
> ...
> Instead of lifetime intersections with `&` (I believe Timon proposed
> that in the original thread)

I didn't. I suggested that _some_ suitable syntax might need to be found. :)

> The root cause of the problem here is the call to `free()`.

(Proving the safety of code containing manual free requires different machinery.)