www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - DConf 2013 Day 1 Talk 2 (Copy and Move Semantics)

reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
Woohoo, Ali's talk is up! Just finished watching it. I have to thank Ali
for a most excellent presentation. Very informative and insightful, and
I learned several really cool things about D that I wasn't even aware of
before:

- to!string doesn't copy when the source is already a string 'cos it's
  immutable. Sweeeet!

- The bit about swapping of structs when assigning a function's return
  value. Makes a lot of sense semantically! Though it does bear looking
  into for further optimizations. What about in-place construction if a
  struct is known to be returned to the caller, so that even the move is
  elided?

- The bit about exception-safe ctors: awesome!! Yet another thing D gets
  right, that blows up in C++.

- Implicit casting to immutable from return value of pure functions --
  that is absolutely awesome, and as Walter said, yes we should
  definitely explore this more. Looks like we can have our cake and eat
  it too!

- The idiom of using this(S that) vs. this(ref const(S) that) for
  move/copy: another awesome idiom that should be documented in a
  prominent place so that more people are aware of it.


T

-- 
Questions are the beginning of intelligence, but the fear of God is the
beginning of wisdom.
May 10 2013
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 05/10/2013 10:03 PM, H. S. Teoh wrote:

 I have to thank Ali
Thank you, it's very kind of you.
 - The bit about swapping of structs when assigning a function's return
    value. Makes a lot of sense semantically! Though it does bear looking
    into for further optimizations.
deadalnix mentioned the same thing: Instead of bit-swapping, it is possible to destroy the old state first and then bit-move from the rvalue. I am pretty sure that is how it is done by the compiler. Still, I find it easier to think about in terms of bit-swapping.
 What about in-place construction if a
    struct is known to be returned to the caller, so that even the move is
    elided?
I think that is the RVO and the NRVO optimization, which is not possible in every case. For example, if I am not mistaken, it is not possible if the fonction returns one of two possible values conditionally (e.g. by the ternary operator).
 - The bit about exception-safe ctors: awesome!! Yet another thing D gets
    right, that blows up in C++.
(Correction: exception-safe _assignment_). As far as I know, I am one of the few who point out the glaring exception-unsafe behavior of the assignment operator of C++. Every C++ programmer knows about "the rule of the big three" (ctor, dtor, assignment) but nobody talks about "the rule of the big one". (assignment) :) For strongly exception-safe assignment, one must always define the assignment operator. (Well, for types that have multiple members and that the ones after the first one may throw. (It is ok if the first one throws; then there would be no partial assignment.))
 - The idiom of using this(S that) vs. this(ref const(S) that) for
    move/copy: another awesome idiom that should be documented in a
    prominent place so that more people are aware of it.
Actually that one is well documented in TDPL. Ali
May 10 2013
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 5/10/2013 11:49 PM, Ali Çehreli wrote:
 As far as I know, I am one of the few who point out the glaring
exception-unsafe
 behavior of the assignment operator of C++.
Since Andrei did the design (copy-swap), I'm sure he's well aware of it!
May 10 2013
parent reply "Diggory" <diggsey googlemail.com> writes:
Just listened to this talk and it made me think about the various 
type qualifiers. Has there ever been any thought of introducing a 
new type qualifier/attribute, "unique"? I know it already exists 
as a standard library class but I think there are several 
advantages to having it as a language feature:

- "unique" objects can be moved into default, const, unique or 
immutable variables, but can never be copied.

- "new"/constructors always returns a "unique" object, which can 
then be moved into any type, completely eliminating the need for 
different types of constructors.

- Functions which create new objects can also return a "unique" 
object solving the problem mentioned in this talk of whether or 
not to return immutable values.

- "assumeUnique" would actually return a "unique" type, but would 
be unnecessary in most cases.

- Strings can be efficiently built in "unique" character arrays 
and then safely returned as immutable without a cast.

- The compiler can actually provide strong guarantees about 
uniqueness compared to the rather weak guarantees possible in 
std.typecons.Unique.

- It can be extremely useful for optimisation if the compiler can 
know that there are no other references to an object. There are 
countless times when this knowledge would make otherwise unsafe 
optimisations safe.
May 11 2013
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 05/11/2013 04:12 AM, Diggory wrote:

 Has there ever been any thought of introducing a new type
 qualifier/attribute, "unique"?
There has been discussions about this idea. Just two on the D.learn newsgroup that mention an experimental UniqueMutable idea: http://forum.dlang.org/thread/itr5o1$poi$1 digitalmars.com http://forum.dlang.org/thread/jd26ig$27qd$1 digitalmars.com?page=2 I am sure there are other on this newsgroup as well. Ali
May 11 2013
parent "deadalnix" <deadalnix gmail.com> writes:
On Saturday, 11 May 2013 at 14:53:39 UTC, Ali Çehreli wrote:
 On 05/11/2013 04:12 AM, Diggory wrote:

 Has there ever been any thought of introducing a new type
 qualifier/attribute, "unique"?
There has been discussions about this idea. Just two on the D.learn newsgroup that mention an experimental UniqueMutable idea: http://forum.dlang.org/thread/itr5o1$poi$1 digitalmars.com http://forum.dlang.org/thread/jd26ig$27qd$1 digitalmars.com?page=2 I am sure there are other on this newsgroup as well. Ali
Microsft have a very good paper on the subject : http://research.microsoft.com/pubs/170528/msr-tr-2012-79.pdf But I don't think this should be implemented before more deep issue are sorted out.
May 11 2013
prev sibling next sibling parent reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On 2013-05-11, 13:12, Diggory wrote:

 Just listened to this talk and it made me think about the various type  
 qualifiers. Has there ever been any thought of introducing a new type  
 qualifier/attribute, "unique"? I know it already exists as a standard  
 library class but I think there are several advantages to having it as a  
 language feature:

 - "unique" objects can be moved into default, const, unique or immutable  
 variables, but can never be copied.

 - "new"/constructors always returns a "unique" object, which can then be  
 moved into any type, completely eliminating the need for different types  
 of constructors.

 - Functions which create new objects can also return a "unique" object  
 solving the problem mentioned in this talk of whether or not to return  
 immutable values.

 - "assumeUnique" would actually return a "unique" type, but would be  
 unnecessary in most cases.

 - Strings can be efficiently built in "unique" character arrays and then  
 safely returned as immutable without a cast.

 - The compiler can actually provide strong guarantees about uniqueness  
 compared to the rather weak guarantees possible in std.typecons.Unique.

 - It can be extremely useful for optimisation if the compiler can know  
 that there are no other references to an object. There are countless  
 times when this knowledge would make otherwise unsafe optimisations safe.
unique is interesting, and holds many promises. However, its effects may be wide-spanning and have many corner case. In addition to mutability, unique applies to shared/unshared - a unique value may safely be moved to another thread. Pure functions whose parameters are all unique or value types will always return a unique result. (Note that this is similar to how pure function results are now implicitly castable to immutable, but unique is stricter) For unique values not to lose unicity when passed to functions, there must be ways to specify that the function will not create new aliases to the passed value. scope might fit the bill here, otherwise something like lent must be added. -- Simen
May 11 2013
parent reply "Diggory" <diggsey googlemail.com> writes:
 unique is interesting, and holds many promises. However, its 
 effects may
 be wide-spanning and have many corner case.

 In addition to mutability, unique applies to shared/unshared - 
 a unique
 value may safely be moved to another thread.

 Pure functions whose parameters are all unique or value types 
 will always
 return a unique result. (Note that this is similar to how pure 
 function
 results are now implicitly castable to immutable, but unique is 
 stricter)

 For unique values not to lose unicity when passed to functions, 
 there
 must be ways to specify that the function will not create new 
 aliases to
 the passed value. scope might fit the bill here, otherwise 
 something like
 lent must be added.
That's solved by the rule that "unique" values can only be moved not copied. To pass a "unique" parameter by value to a function the original must be invalidated in the process. The only other way would be to pass by reference, in which case the function argument must also be declared "unique". The rule about pure functions returning "unique" is not in general true - if it returns a class which has a pointer to itself, or a pointer to another class which has a pointer to itself then the return value is not unique. The return value must specifically be declared unique. The only problem I can see is with the "this" pointer: - If we have unique and non-unique functions it means duplicating everything, or at least remembering to add the "unique" attribute. - Unique would then be both a type modifier and a function attribute - It's not immediately obvious what operations can be performed by a "unique" member function. - It is not simply equivalent to marking the "this" parameter as unique because that would mean erasing the argument passed in for that parameter, ie. invalidating the object! But I think that can also be solved satisfactorily: - Make the unique-ness of a member function something which is implicitly determined by the compiler based on its content. - Any function which only dereferences the "this" pointer can safely be marked "unique" internally, and therefore can be called on a unique variable. If it copies the "this" pointer (auto x = this) then it is not "unique".
May 11 2013
parent reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On 2013-05-11, 23:40, Diggory wrote:

 unique is interesting, and holds many promises. However, its effects may
 be wide-spanning and have many corner case.

 In addition to mutability, unique applies to shared/unshared - a unique
 value may safely be moved to another thread.

 Pure functions whose parameters are all unique or value types will  
 always
 return a unique result. (Note that this is similar to how pure function
 results are now implicitly castable to immutable, but unique is  
 stricter)

 For unique values not to lose unicity when passed to functions, there
 must be ways to specify that the function will not create new aliases to
 the passed value. scope might fit the bill here, otherwise something  
 like
 lent must be added.
That's solved by the rule that "unique" values can only be moved not copied.
What is? The last part?
 To pass a "unique" parameter by value to a function the original must be  
 invalidated in the process. The only other way would be to pass by  
 reference, in which case the function argument must also be declared  
 "unique".
In which case we end up with duplicates of all functions to support both unique and non-unique parameters. Hence we'd need scope or lent.
 The rule about pure functions returning "unique" is not in general true  
 - if it returns a class which has a pointer to itself, or a pointer to  
 another class which has a pointer to itself then the return value is not  
 unique. The return value must specifically be declared unique.
I'm not convinced. unique, like const or immutable, is transitive. If foo is unique, then so is foo.bar.
 The only problem I can see is with the "this" pointer:
 - If we have unique and non-unique functions it means duplicating  
 everything, or at least remembering to add the "unique" attribute.
 - Unique would then be both a type modifier and a function attribute
 - It's not immediately obvious what operations can be performed by a  
 "unique" member function.
 - It is not simply equivalent to marking the "this" parameter as unique  
 because that would mean erasing the argument passed in for that  
 parameter, ie. invalidating the object!
Look above again. With 'lent', the function guarantees not to create new, escaping aliases. Thus, a unique value may be passed by ref (e.g. the 'this' pointer) without erasing the value. The syntax would thus be: class A { void forble() lent { globalValue = this; // Compile-time error. } }
 But I think that can also be solved satisfactorily:
 - Make the unique-ness of a member function something which is  
 implicitly determined by the compiler based on its content.
Won't work. The function body is not always available.
 - Any function which only dereferences the "this" pointer can safely be  
 marked "unique" internally, and therefore can be called on a unique  
 variable. If it copies the "this" pointer (auto x = this) then it is not  
 "unique".
Temporary copies are fine. Only those that escape the function are problematic. -- Simen
May 11 2013
next sibling parent reply "Diggory" <diggsey googlemail.com> writes:
On Saturday, 11 May 2013 at 22:24:38 UTC, Simen Kjaeraas wrote:
 In which case we end up with duplicates of all functions to 
 support both
 unique and non-unique parameters. Hence we'd need scope or lent.
OK, I see that we need a way to accept unique values without enforcing them.
 Temporary copies are fine. Only those that escape the function 
 are
 problematic.
The problem I had with this is that it temporarily breaks the invariant on the calling code's "unique" variable. For the duration of the function it is no longer unique. One way to not break the invariant would be to imagine it as first moving the value into the function when it is called, and then moving it back out when it returns. Obviously it may not be good to actually implement it this way, but all that is necessary is to make accessing the original variable before the function has returned, undefined. In most cases the only limit this imposes is not passing a "unique" variable for more than one argument to a function. The problem is when there is a global "unique" variable being passed to a function. Perhaps in this case the compiler could actually emulate the move operation in and out of the function by temporarily clearing the global for the duration of the call so that it can't then be accessed by the function, thus maintaining the unique invariant.
 Can you detail the process involved in assignment from one 
 unique to
 another unique? Would the original unique be destroyed? Leaving 
 only the
 'copy' remaining?
Yep, it would just be standard "move" semantics, same as if you initialise a variable with an rvalue.
 It's been brought up quite a few times (it might have even have 
 been brought
 up by Bartoz ages ago - I don't recall for sure). The problem 
 is that it
 complicates the type system yet further. We'd have to find a 
 way to introduce
 it without impacting the rest of the type system much or 
 complicating it much
 further. And that's a tall order. Not to mention, we already 
 have a lot of
 attributes, and every new one adds to the complexity and 
 cognitive load of the
 language. So, we have to be very careful about what we do and 
 don't add at
 this point.

 - Jonathan M Davis
The main change to existing code would seem to be adding "scope" or "lent" to parameters where relevant so that unique values can be accepted. It only makes sense to use it for ref parameters, classes and slices, so it's not like it would need to be added everywhere. Interestingly that's yet another optimisation that can be done - if a slice is unique it can freely be appended to without some of the usual checks. With regard to lots of attributes, I think a language which tries to be as much as D tries to be is going to end up with a lot of attributes in the end anyway. With a combination of better IDE and compiler support for inferring attributes, it shouldn't cause too much of a problem - attributes are generally very simple to understand, the hard part is always knowing which one to apply when writing library code. It's not just for the benefit of the compiler either - attributes help get across the intent of the code rather than just what it does and can be very powerful in ensuring correct code.
May 11 2013
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, May 12, 2013 02:36:28 Diggory wrote:
 It's not just for the benefit of the compiler either - attributes
 help get across the intent of the code rather than just what it
 does and can be very powerful in ensuring correct code.
Yes, but the more you have, the more the programmer has to understand and keep track of. There's cost in cognitive load. So, you want to add enough that you can do what you need to do and get some solid benefits from the attributes that you have, but at some point, you have to stop adding them, or the language becomes unwieldy. Whether it would ultimately be good or bad with regards to unique specifically is still an open question, but it means that any attributes you add really need to pull their weight, especially when we already have so many of them. - Jonathan M Davis
May 11 2013
prev sibling parent reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On 2013-05-12, 02:36, Diggory wrote:

 Temporary copies are fine. Only those that escape the function are
 problematic.
The problem I had with this is that it temporarily breaks the invariant on the calling code's "unique" variable. For the duration of the function it is no longer unique.
This is basically the same as with D's pure. You may break purity as much as you like, as long as no side effects are visible *outside* the function.
 One way to not break the invariant would be to imagine it as first  
 moving the value into the function when it is called, and then moving it  
 back out when it returns.

 Obviously it may not be good to actually implement it this way, but all  
 that is necessary is to make accessing the original variable before the  
 function has returned, undefined. In most cases the only limit this  
 imposes is not passing a "unique" variable for more than one argument to  
 a function.
Hm. I didn't think of that. I believe passing the same unique value twice should be fine, as long as both are lent. Obviously, in the case of non-lent, passing it twice should be an error (probably not possible to statically determine in all cases, so a runtime error occasionally, or just go conservative and outlaw some valid uses).
 The problem is when there is a global "unique" variable being passed to  
 a function. Perhaps in this case the compiler could actually emulate the  
 move operation in and out of the function by temporarily clearing the  
 global for the duration of the call so that it can't then be accessed by  
 the function, thus maintaining the unique invariant.
I believe you're overthinking this. First, what is global unique variable? A unique value will per definition have to be thread-local (if not, other threads have a reference to it, and it's not unique). Thus, when passed to a function, the value is inaccessible outside of that function until it returns. (I guess fibers might be an exception here?) -- Simen
May 11 2013
parent reply "Diggory" <diggsey googlemail.com> writes:
On Sunday, 12 May 2013 at 01:16:43 UTC, Simen Kjaeraas wrote:
 I believe you're overthinking this. First, what is global 
 unique variable?
 A unique value will per definition have to be thread-local (if 
 not, other
 threads have a reference to it, and it's not unique). Thus, 
 when passed to
 a function, the value is inaccessible outside of that function 
 until it
 returns. (I guess fibers might be an exception here?)
While in the function, that function can access a value both through the global variable which is supposed to be "unique" and through the lent parameter. This could cause problems because "unique" no longer means "unique", although it's difficult to see how serious that might be.
May 11 2013
parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On 2013-05-12, 05:16, Diggory wrote:

 On Sunday, 12 May 2013 at 01:16:43 UTC, Simen Kjaeraas wrote:
 I believe you're overthinking this. First, what is global unique  
 variable?
 A unique value will per definition have to be thread-local (if not,  
 other
 threads have a reference to it, and it's not unique). Thus, when passed  
 to
 a function, the value is inaccessible outside of that function until it
 returns. (I guess fibers might be an exception here?)
While in the function, that function can access a value both through the global variable which is supposed to be "unique" and through the lent parameter. This could cause problems because "unique" no longer means "unique", although it's difficult to see how serious that might be.
Ah, like that. That's the same problem as passing the same unique value twice as a parameter to a function, I believe. Let's try: class A {} unique A globalA; A globalNonUnique; void foo() { bar( globalA ); } void bar(lent A localA) { globalNonUnique = globalA; // Where the good stuff happens. } At the point of the comment, globalA is null, because of unique's rules. localA is still what it was, because it's lent, which gives no uniqueness guarantees, only that no new, escaping references be created. If the parameter had been marked unique instead of lent, globalA would have been cleared upon its value being passed to the function. I believe the elephant in the room is lent return values: lent A baz(lent A a) { return a; // Obviously illegal - a new alias is created. } lent A qux(ref lent A a) { return a; // Sets a to null and returns its old value? } -- Simen
May 12 2013
prev sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Saturday, 11 May 2013 at 22:24:38 UTC, Simen Kjaeraas wrote:
 I'm not convinced. unique, like const or immutable, is 
 transitive. If foo
 is unique, then so is foo.bar.
That isn't true. Please read microsoft's paper.
May 11 2013
next sibling parent reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On 2013-05-12, 08:12, deadalnix wrote:

 On Saturday, 11 May 2013 at 22:24:38 UTC, Simen Kjaeraas wrote:
 I'm not convinced. unique, like const or immutable, is transitive. If  
 foo
 is unique, then so is foo.bar.
That isn't true. Please read microsoft's paper.
Done. *Mostly* transitive, then. Anything reachable through a unique reference is either unique or immutable. -- Simen
May 12 2013
next sibling parent reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On 2013-05-12, 11:50, deadalnix wrote:

 On Sunday, 12 May 2013 at 09:10:56 UTC, Simen Kjaeraas wrote:
 On 2013-05-12, 08:12, deadalnix wrote:

 On Saturday, 11 May 2013 at 22:24:38 UTC, Simen Kjaeraas wrote:
 I'm not convinced. unique, like const or immutable, is transitive. If  
 foo
 is unique, then so is foo.bar.
That isn't true. Please read microsoft's paper.
Done. *Mostly* transitive, then. Anything reachable through a unique reference is either unique or immutable.
No. Think about it : when you reach something via a uniq pointer, it is by definition not unique as you have 2 copies of it, because you just accessed it. Plus the unique pointer refers to a unique mutable graph of object. A object into that graph can have several object into the graph refereing to it. You are wrong in 2 different ways.
I'd argue it's only one way, if only to reduce the impact to my ego. :p Yes, you're absolutely right. Anything reachable through a unique reference needs to be *lent* or immutable. That way, it's either safe to create new references to it, or the type system forbids it. -- Simen
May 12 2013
parent "Thiez" <thiezz gmail.com> writes:
You may wish to take a look at Rust for inspiration. Rust has 
unique (~) pointers and has made some interesting choices there. 
Their ~pointers imply ownership. I'm not sure this could be 
(efficiently) duplicated in a library for D (Rust has significant 
compiler support for its pointer types) but it may be worth 
taking a look regardless.
May 12 2013
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 5/12/13 5:10 AM, Simen Kjaeraas wrote:
 On 2013-05-12, 08:12, deadalnix wrote:

 On Saturday, 11 May 2013 at 22:24:38 UTC, Simen Kjaeraas wrote:
 I'm not convinced. unique, like const or immutable, is transitive. If
 foo
 is unique, then so is foo.bar.
That isn't true. Please read microsoft's paper.
Done. *Mostly* transitive, then. Anything reachable through a unique reference is either unique or immutable.
Bartosz, Walter and I reached a similar design a few years ago. We just thought it complicates things too much for what it does. Andrei
May 12 2013
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 5/12/2013 6:01 AM, Andrei Alexandrescu wrote:
 Bartosz, Walter and I reached a similar design a few years ago. We just thought
 it complicates things too much for what it does.
I've been working in the background on a scheme that can infer uniqueness. The beauty of it is it will not require visible language changes - it's just that things that didn't compile before now will. It won't solve all the problems, but I'm hoping it'll solve enough that the rest will not be more than a minor annoyance. For a trivial example, shared p = new int; would work, as 'new int' would be inferred to be unique, and a unique pointer can be implicitly cast to immutable or shared. This plays to D's strength with function purity, transitive const/immutable/shared, attribute inference, etc.
May 12 2013
next sibling parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
13-May-2013 00:28, Walter Bright пишет:
 On 5/12/2013 6:01 AM, Andrei Alexandrescu wrote:
 Bartosz, Walter and I reached a similar design a few years ago. We
 just thought
 it complicates things too much for what it does.
I've been working in the background on a scheme that can infer uniqueness. The beauty of it is it will not require visible language changes - it's just that things that didn't compile before now will.
Good things these are, but that adds up to what a programmer should know or we are stuck trying out combinations that might work until we hit it. -- Dmitry Olshansky
May 12 2013
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 5/12/2013 1:48 PM, Dmitry Olshansky wrote:
 13-May-2013 00:28, Walter Bright пишет:
 On 5/12/2013 6:01 AM, Andrei Alexandrescu wrote:
 Bartosz, Walter and I reached a similar design a few years ago. We
 just thought
 it complicates things too much for what it does.
I've been working in the background on a scheme that can infer uniqueness. The beauty of it is it will not require visible language changes - it's just that things that didn't compile before now will.
Good things these are, but that adds up to what a programmer should know or we are stuck trying out combinations that might work until we hit it.
I think programmers will find it to be intuitive, not magical.
May 12 2013
parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
13-May-2013 02:47, Walter Bright пишет:
 On 5/12/2013 1:48 PM, Dmitry Olshansky wrote:
 13-May-2013 00:28, Walter Bright пишет:
 On 5/12/2013 6:01 AM, Andrei Alexandrescu wrote:
 Bartosz, Walter and I reached a similar design a few years ago. We
 just thought
 it complicates things too much for what it does.
I've been working in the background on a scheme that can infer uniqueness. The beauty of it is it will not require visible language changes - it's just that things that didn't compile before now will.
Good things these are, but that adds up to what a programmer should know or we are stuck trying out combinations that might work until we hit it.
I think programmers will find it to be intuitive, not magical.
By the end of day we need guarantees not intuition which is the problem. Compare the statement in the would be standard of D: "If the compiler can prove that the expression is unique it's implicitly convertible to shared/immutable/const." vs "The following rules define what kinds of if the expression is unique. [...] Unique expression is convertible to shared/immutable/const." The keyword "the compiler can prove" - it doesn't state anything reliable. In the long run I'd prefer the second and exact formal rules and if they are too hard to explain we'd better not do it at all. -- Dmitry Olshansky
May 12 2013
parent Walter Bright <newshound2 digitalmars.com> writes:
On 5/12/2013 11:11 PM, Dmitry Olshansky wrote:
 In the long run I'd prefer the second and exact formal rules and if they are
too
 hard to explain we'd better not do it at all.
I agree that formal rules are better. I'm working on it.
May 12 2013
prev sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Sunday, 12 May 2013 at 20:28:56 UTC, Walter Bright wrote:
 On 5/12/2013 6:01 AM, Andrei Alexandrescu wrote:
 Bartosz, Walter and I reached a similar design a few years 
 ago. We just thought
 it complicates things too much for what it does.
I've been working in the background on a scheme that can infer uniqueness. The beauty of it is it will not require visible language changes - it's just that things that didn't compile before now will. It won't solve all the problems, but I'm hoping it'll solve enough that the rest will not be more than a minor annoyance. For a trivial example, shared p = new int; would work, as 'new int' would be inferred to be unique, and a unique pointer can be implicitly cast to immutable or shared. This plays to D's strength with function purity, transitive const/immutable/shared, attribute inference, etc.
It smell like an ad hoc solution that will be completely undefined.
May 13 2013
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 5/13/13 3:06 AM, deadalnix wrote:
 On Sunday, 12 May 2013 at 20:28:56 UTC, Walter Bright wrote:
 On 5/12/2013 6:01 AM, Andrei Alexandrescu wrote:
 Bartosz, Walter and I reached a similar design a few years ago. We
 just thought
 it complicates things too much for what it does.
I've been working in the background on a scheme that can infer uniqueness. The beauty of it is it will not require visible language changes - it's just that things that didn't compile before now will. It won't solve all the problems, but I'm hoping it'll solve enough that the rest will not be more than a minor annoyance. For a trivial example, shared p = new int; would work, as 'new int' would be inferred to be unique, and a unique pointer can be implicitly cast to immutable or shared. This plays to D's strength with function purity, transitive const/immutable/shared, attribute inference, etc.
It smell like an ad hoc solution that will be completely undefined.
To me it sounds like anything but. Walter explained the idea to me and it's definitely worth exploring. We will work together on a DIP. Andrei
May 13 2013
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 5/12/13 5:50 AM, deadalnix wrote:
 On Sunday, 12 May 2013 at 09:10:56 UTC, Simen Kjaeraas wrote:
 On 2013-05-12, 08:12, deadalnix wrote:

 On Saturday, 11 May 2013 at 22:24:38 UTC, Simen Kjaeraas wrote:
 I'm not convinced. unique, like const or immutable, is transitive.
 If foo
 is unique, then so is foo.bar.
That isn't true. Please read microsoft's paper.
Done. *Mostly* transitive, then. Anything reachable through a unique reference is either unique or immutable.
No. Think about it : when you reach something via a uniq pointer, it is by definition not unique as you have 2 copies of it, because you just accessed it.
I don't think so. Lent and destructive read can be used.
 Plus the unique pointer refers to a unique mutable graph of object. A
 object into that graph can have several object into the graph refereing
 to it.
Correct. Andrei
May 12 2013
parent "deadalnix" <deadalnix gmail.com> writes:
On Sunday, 12 May 2013 at 13:07:15 UTC, Andrei Alexandrescu wrote:
 On 5/12/13 5:50 AM, deadalnix wrote:
 On Sunday, 12 May 2013 at 09:10:56 UTC, Simen Kjaeraas wrote:
 On 2013-05-12, 08:12, deadalnix wrote:

 On Saturday, 11 May 2013 at 22:24:38 UTC, Simen Kjaeraas 
 wrote:
 I'm not convinced. unique, like const or immutable, is 
 transitive.
 If foo
 is unique, then so is foo.bar.
That isn't true. Please read microsoft's paper.
Done. *Mostly* transitive, then. Anything reachable through a unique reference is either unique or immutable.
No. Think about it : when you reach something via a uniq pointer, it is by definition not unique as you have 2 copies of it, because you just accessed it.
I don't think so. Lent and destructive read can be used.
Destructive read would be super confusing and due to the Correct point below, don't ensure anything.
 Plus the unique pointer refers to a unique mutable graph of 
 object. A
 object into that graph can have several object into the graph 
 refereing
 to it.
Correct.
May 12 2013
prev sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On 2013-05-12, 11:10, Simen Kjaeraas wrote:

 On 2013-05-12, 08:12, deadalnix wrote:

 On Saturday, 11 May 2013 at 22:24:38 UTC, Simen Kjaeraas wrote:
 I'm not convinced. unique, like const or immutable, is transitive. If  
 foo
 is unique, then so is foo.bar.
That isn't true. Please read microsoft's paper.
Done. *Mostly* transitive, then. Anything reachable through a unique reference is either unique or immutable.
btw, we're free to define unique to be completely transitive, or even not transitive at all. We need not end up with a carbon copy of Microsoft's system. -- Simen
May 12 2013
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
On 11 May 2013 21:12, Diggory <diggsey googlemail.com> wrote:

 Just listened to this talk and it made me think about the various type
 qualifiers. Has there ever been any thought of introducing a new type
 qualifier/attribute, "unique"? I know it already exists as a standard
 library class but I think there are several advantages to having it as a
 language feature:

 - "unique" objects can be moved into default, const, unique or immutable
 variables, but can never be copied.

 - "new"/constructors always returns a "unique" object, which can then be
 moved into any type, completely eliminating the need for different types of
 constructors.

 - Functions which create new objects can also return a "unique" object
 solving the problem mentioned in this talk of whether or not to return
 immutable values.

 - "assumeUnique" would actually return a "unique" type, but would be
 unnecessary in most cases.

 - Strings can be efficiently built in "unique" character arrays and then
 safely returned as immutable without a cast.

 - The compiler can actually provide strong guarantees about uniqueness
 compared to the rather weak guarantees possible in std.typecons.Unique.

 - It can be extremely useful for optimisation if the compiler can know
 that there are no other references to an object. There are countless times
 when this knowledge would make otherwise unsafe optimisations safe.
This is a very interesting idea. It would also be a massive advantage when passing ownership between threads, which is a long-standing problem that's not solves at all. There currently exists no good way to say "I now give ownership to you", which is what you basically always do when putting a job on a queue to be picked up by some foreign thread. Using shared is cumbersome, and feels very inelegant, casts everywhere, and once the casts appear, any safety is immediately lost. Can you detail the process involved in assignment from one unique to another unique? Would the original unique be destroyed? Leaving only the 'copy' remaining?
May 11 2013
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, May 11, 2013 13:12:00 Diggory wrote:
 Just listened to this talk and it made me think about the various
 type qualifiers. Has there ever been any thought of introducing a
 new type qualifier/attribute, "unique"?
It's been brought up quite a few times (it might have even have been brought up by Bartoz ages ago - I don't recall for sure). The problem is that it complicates the type system yet further. We'd have to find a way to introduce it without impacting the rest of the type system much or complicating it much further. And that's a tall order. Not to mention, we already have a lot of attributes, and every new one adds to the complexity and cognitive load of the language. So, we have to be very careful about what we do and don't add at this point. - Jonathan M Davis
May 11 2013
prev sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On 2013-05-12, 00:31, Manu wrote:

 This is a very interesting idea.
 It would also be a massive advantage when passing ownership between
 threads, which is a long-standing problem that's not solves at all.
 There currently exists no good way to say "I now give ownership to you",
 which is what you basically always do when putting a job on a queue to be
 picked up by some foreign thread.
 Using shared is cumbersome, and feels very inelegant, casts everywhere,  
 and
 once the casts appear, any safety is immediately lost.

 Can you detail the process involved in assignment from one unique to
 another unique? Would the original unique be destroyed? Leaving only the
 'copy' remaining?
Not speaking for Diggory, but that's generally the idea, yes. In code: class A { /* ... */ } void foo(A a) { /* ... */ } void fun( ) { unique A a = new A(); unique A b = a; assert(a is null); foo(b); assert(b is null); } And with my suggestion for 'lent': void bar(lent A a) { /* Assigning a (or anything reachable from a) to a global in here is verboten. */ } void gun( ) { unique A a = new A(); bar(a); assert(a !is null); } -- Simen
May 11 2013