digitalmars.D - DConf 2013 Day 1 Talk 2 (Copy and Move Semantics)
- H. S. Teoh (23/23) May 10 2013 Woohoo, Ali's talk is up! Just finished watching it. I have to thank Ali
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (21/33) May 10 2013 deadalnix mentioned the same thing: Instead of bit-swapping, it is
- Walter Bright (2/4) May 10 2013 Since Andrei did the design (copy-swap), I'm sure he's well aware of it!
- Diggory (24/24) May 11 2013 Just listened to this talk and it made me think about the various
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (7/9) May 11 2013 There has been discussions about this idea. Just two on the D.learn
- deadalnix (5/16) May 11 2013 Microsft have a very good paper on the subject :
- Simen Kjaeraas (14/36) May 11 2013 unique is interesting, and holds many promises. However, its effects may
- Diggory (27/46) May 11 2013 That's solved by the rule that "unique" values can only be moved
- Simen Kjaeraas (20/64) May 11 2013 In which case we end up with duplicates of all functions to support both
- Diggory (39/66) May 11 2013 OK, I see that we need a way to accept unique values without
- Jonathan M Davis (10/13) May 11 2013 Yes, but the more you have, the more the programmer has to understand an...
- Simen Kjaeraas (16/34) May 11 2013 This is basically the same as with D's @pure. You may break purity as
- Diggory (6/15) May 11 2013 While in the function, that function can access a value both
- Simen Kjaeraas (27/40) May 12 2013 Ah, like that. That's the same problem as passing the same unique value
- deadalnix (2/5) May 11 2013 That isn't true. Please read microsoft's paper.
- Simen Kjaeraas (5/11) May 12 2013 Done. *Mostly* transitive, then. Anything reachable through a unique
- Simen Kjaeraas (7/28) May 12 2013 I'd argue it's only one way, if only to reduce the impact to my ego. :p
- Thiez (6/6) May 12 2013 You may wish to take a look at Rust for inspiration. Rust has
- Andrei Alexandrescu (4/14) May 12 2013 Bartosz, Walter and I reached a similar design a few years ago. We just
- Walter Bright (10/12) May 12 2013 I've been working in the background on a scheme that can infer uniquenes...
- Dmitry Olshansky (5/12) May 12 2013 Good things these are, but that adds up to what a programmer should know...
- Walter Bright (2/13) May 12 2013 I think programmers will find it to be intuitive, not magical.
- Dmitry Olshansky (13/28) May 12 2013 By the end of day we need guarantees not intuition which is the problem.
- Walter Bright (2/4) May 12 2013 I agree that formal rules are better. I'm working on it.
- deadalnix (3/19) May 13 2013 It smell like an ad hoc solution that will be completely
- Andrei Alexandrescu (4/25) May 13 2013 To me it sounds like anything but. Walter explained the idea to me and
- Andrei Alexandrescu (4/24) May 12 2013 Correct.
- deadalnix (3/35) May 12 2013 Destructive read would be super confusing and due to the Correct
- Simen Kjaeraas (6/16) May 12 2013 btw, we're free to define unique to be completely transitive, or even
- Manu (12/34) May 11 2013 This is a very interesting idea.
- Jonathan M Davis (10/13) May 11 2013 It's been brought up quite a few times (it might have even have been bro...
- Simen Kjaeraas (21/33) May 11 2013 Not speaking for Diggory, but that's generally the idea, yes. In code:
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
On 05/10/2013 10:03 PM, H. S. Teoh wrote:I have to thank AliThank 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
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
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
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
On Saturday, 11 May 2013 at 14:53:39 UTC, Ali Çehreli wrote:On 05/11/2013 04:12 AM, Diggory wrote: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.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
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
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
On 2013-05-11, 23:40, Diggory wrote:What is? The last part?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".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
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 DavisThe 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
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
On 2013-05-12, 02:36, Diggory wrote: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.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.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
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
On 2013-05-12, 05:16, Diggory wrote:On Sunday, 12 May 2013 at 01:16:43 UTC, Simen Kjaeraas wrote: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? } -- SimenI 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 12 2013
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
On 2013-05-12, 08:12, deadalnix wrote:On Saturday, 11 May 2013 at 22:24:38 UTC, Simen Kjaeraas wrote:Done. *Mostly* transitive, then. Anything reachable through a unique reference is either unique or immutable. -- SimenI'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 12 2013
On 2013-05-12, 11:50, deadalnix wrote:On Sunday, 12 May 2013 at 09:10:56 UTC, Simen Kjaeraas wrote: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. -- SimenOn 2013-05-12, 08:12, deadalnix wrote: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.On Saturday, 11 May 2013 at 22:24:38 UTC, Simen Kjaeraas wrote:Done. *Mostly* transitive, then. Anything reachable through a unique reference is either unique or immutable.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 12 2013
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
On 5/12/13 5:10 AM, Simen Kjaeraas wrote:On 2013-05-12, 08:12, deadalnix 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. AndreiOn Saturday, 11 May 2013 at 22:24:38 UTC, Simen Kjaeraas wrote:Done. *Mostly* transitive, then. Anything reachable through a unique reference is either unique or immutable.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 12 2013
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
13-May-2013 00:28, Walter Bright пишет:On 5/12/2013 6:01 AM, Andrei Alexandrescu wrote: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 OlshanskyBartosz, 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.
May 12 2013
On 5/12/2013 1:48 PM, Dmitry Olshansky wrote:13-May-2013 00:28, Walter Bright пишет:I think programmers will find it to be intuitive, not magical.On 5/12/2013 6:01 AM, Andrei Alexandrescu wrote: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.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.
May 12 2013
13-May-2013 02:47, Walter Bright пишет:On 5/12/2013 1:48 PM, Dmitry Olshansky wrote: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 Olshansky13-May-2013 00:28, Walter Bright пишет:I think programmers will find it to be intuitive, not magical.On 5/12/2013 6:01 AM, Andrei Alexandrescu wrote: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.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.
May 12 2013
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
On Sunday, 12 May 2013 at 20:28:56 UTC, Walter Bright wrote:On 5/12/2013 6:01 AM, Andrei Alexandrescu wrote:It smell like an ad hoc solution that will be completely undefined.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 13 2013
On 5/13/13 3:06 AM, deadalnix wrote:On Sunday, 12 May 2013 at 20:28:56 UTC, Walter Bright wrote: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. AndreiOn 5/12/2013 6:01 AM, Andrei Alexandrescu wrote:It smell like an ad hoc solution that will be completely undefined.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 13 2013
On 5/12/13 5:50 AM, deadalnix wrote:On Sunday, 12 May 2013 at 09:10:56 UTC, Simen Kjaeraas wrote:I don't think so. Lent and destructive read can be used.On 2013-05-12, 08:12, deadalnix wrote: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.On Saturday, 11 May 2013 at 22:24:38 UTC, Simen Kjaeraas wrote:Done. *Mostly* transitive, then. Anything reachable through a unique reference is either unique or immutable.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.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
On Sunday, 12 May 2013 at 13:07:15 UTC, Andrei Alexandrescu wrote:On 5/12/13 5:50 AM, deadalnix wrote:Destructive read would be super confusing and due to the Correct point below, don't ensure anything.On Sunday, 12 May 2013 at 09:10:56 UTC, Simen Kjaeraas wrote:I don't think so. Lent and destructive read can be used.On 2013-05-12, 08:12, deadalnix wrote: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.On Saturday, 11 May 2013 at 22:24:38 UTC, Simen Kjaeraas wrote:Done. *Mostly* transitive, then. Anything reachable through a unique reference is either unique or immutable.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.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
On 2013-05-12, 11:10, Simen Kjaeraas wrote:On 2013-05-12, 08:12, deadalnix wrote: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. -- SimenOn Saturday, 11 May 2013 at 22:24:38 UTC, Simen Kjaeraas wrote:Done. *Mostly* transitive, then. Anything reachable through a unique reference is either unique or immutable.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 12 2013
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
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
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