digitalmars.D - DIP77 - Fix unsafe RC pass by 'ref'
- Walter Bright (1/1) Apr 08 2015 http://wiki.dlang.org/DIP77
- weaselcat (2/3) Apr 08 2015 Deceptively simple solution for a hard problem.
- deadalnix (3/4) Apr 08 2015 That is pretty much the old Rust solution called boxing. This
- Walter Bright (9/13) Apr 08 2015 Yes, it's equivalent to it. I had started with doing an INC/DEC pair, bu...
- Brad Anderson (2/6) Apr 08 2015 Any idea why they abandoned it?
- Walter Bright (2/9) Apr 08 2015 No, but I can guess. It's less efficient.
- deadalnix (4/16) Apr 08 2015 This and the fact that they want to prevent multiple writable
- weaselcat (4/7) Apr 08 2015 Does that mean the lifetime of tmp is tied to the scope of the
- Walter Bright (3/9) Apr 08 2015 The same as that of a tmp being returned from a function - to the end of...
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (6/8) Apr 09 2015 But how will this work with anything that makes RCArrays
- Walter Bright (4/11) Apr 09 2015 It examines the types of all mutable values available to the function.
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (4/12) Apr 09 2015 So if I pass in a graph, linked list or a tree, then it will scan
- deadalnix (4/18) Apr 09 2015 No, but indeed, passing down indirection require boxing too. The
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (16/18) Apr 10 2015 Not sure what you mean by boxing. Usually it means that you wrap
- Walter Bright (5/8) Apr 10 2015 Nope. It'll scan at compile time the types reachable through the paramet...
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (7/11) Apr 10 2015 But how can this work? If I provide 2 ref parameters to different
- Walter Bright (5/14) Apr 10 2015 Because with two parameters, if one is a ref coming from an RCO rc1, and...
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (9/15) Apr 10 2015 ref1 -> RCO1 -> N1 -> RCRef1 -> RCO2 -> N2 -> RCRef3 -> RCO3 -> N3
- Walter Bright (3/18) Apr 10 2015 ref2 is copied.
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (3/4) Apr 10 2015 You cannot copy a resource like a memfile. It is already closed
- Walter Bright (3/7) Apr 10 2015 Please read the DIP again. The copy happens earlier.
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (4/5) Apr 10 2015 But one cannot keep a stateful resource alive by copying memory.
- Walter Bright (3/8) Apr 10 2015 That's what ref counting is about.
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (2/3) Apr 10 2015 That would require pervasive ref-counting.
- Marco Leise (7/11) Apr 11 2015 Am Fri, 10 Apr 2015 14:04:39 +0000
- deadalnix (2/11) Apr 11 2015 Ownership, GC.
- Marco Leise (12/26) May 01 2015 That doesn't convince me yet. GC is just incorrect to use here.
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (9/10) Apr 09 2015 I've only skimmed this, but:
- deadalnix (5/8) Apr 09 2015 You yield both caller and callee, so you'll get caller's boxing
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (7/16) Apr 09 2015 But the coroutine stack and everything on it will be intact when
- Michel Fortin (38/39) Apr 09 2015 In the definition of a Reference Counted Object:
- Walter Bright (8/34) Apr 09 2015 "Andrei's idea was to not do the copy for @system opAssign's, thus provi...
- w0rp (6/8) Apr 09 2015 A struct could have a postblit defined if you are implementing
- Walter Bright (5/11) Apr 09 2015 I'm not sure why you'd do that, either. Just make the memory part ref co...
- deadalnix (18/27) Apr 09 2015 In C++, the only real purpose of template were generic
- Walter Bright (15/37) Apr 09 2015 Because the charter of @system is "the user supplies the memory safety",...
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (6/9) Apr 10 2015 I think it's safe to say that if even Rust with its linear type
- Michel Fortin (42/44) Apr 10 2015 Because reference counting has tradoffs, or because someone translates
- Walter Bright (2/17) Apr 10 2015 The copy would be made of array, not Big.
- Martin Nowak (4/9) Apr 10 2015 It seems to only fit to RCO, I'm not positive though.
- Zach the Mystic (17/18) Apr 09 2015 From the DIP:
- ixid (5/6) Apr 10 2015 We seem to be incrementally edging towards Rust's memory
- w0rp (2/8) Apr 10 2015 extern(Rust) embraceExtendExtinguish();
- Walter Bright (3/8) Apr 10 2015 As I explained to deadalnix in this thread, D's semantics in this regard...
- Andrei Alexandrescu (2/7) Apr 10 2015 We hope to do better than Rust. -- Andrei
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (15/16) Apr 11 2015 Hope does not cut it.
- Martin Nowak (11/12) Apr 10 2015 So someone passes an RCO via ref to avoid the inc/dec, and
- Walter Bright (3/9) Apr 10 2015 That's what we have now. It's not good enough.
- Martin Nowak (8/19) Apr 10 2015 Maybe I'm missing something, but this proposal seems to make `ref RCO`
- Walter Bright (3/19) Apr 10 2015 That's kind of throwing in the towel, isn't it?
- weaselcat (3/7) Apr 10 2015 This actually sounds quite logical to me - passing an RC object
- deadalnix (4/16) Apr 10 2015 Only the first pass by ref create a copy. You can then pass the
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (3/23) Apr 11 2015 It's not acceptable that it happens behind the user's back.
- Walter Bright (2/4) Apr 11 2015 Don't know of a better solution.
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (7/13) Apr 11 2015 How about this?
- matovitch (12/26) Apr 11 2015 Just passing, a bit off topic and clearly not familiar enough
- Andrei Alexandrescu (2/7) Apr 11 2015 Expensive opAssign or expensive postblit? -- Andrei
- matovitch (6/16) Apr 12 2015 Well both in the example given by w0rp. I guess D as no "rule of
- Walter Bright (3/14) Apr 12 2015 A quick read of this suggests it is doing the Rust model of only one mut...
- matovitch (3/6) Apr 12 2015 I would love to see a storage class to add the rust ownership
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (18/24) Apr 12 2015 I think it is. You have to keep in mind that this is opt-in; it
- bearophile (6/11) Apr 12 2015 I think D Zen asks for safety on default and opt-out on request.
- Martin Nowak (3/4) Apr 12 2015 Marc talked about unique ownership vs. shared ownership, not
- Martin Nowak (9/16) Apr 12 2015 It's a very good ownership model IMO, because it has no runtime
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (7/11) Apr 12 2015 I'm aware of it, but didn't want to open another can of worms. I
- w0rp (36/61) Apr 11 2015 If we somehow know for a fact that the object really is a
- weaselcat (3/5) Apr 11 2015 I believe it's still defined by DIP74?
- deadalnix (2/4) Apr 11 2015 Nothing is costly here.
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (3/7) Apr 12 2015 Of course it is:
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (26/27) Apr 10 2015 In general, this is way too much focused on reference counting.
- Walter Bright (8/31) Apr 10 2015 A difficulty with that is the semantics will change as the compiler impr...
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (36/92) Apr 10 2015 I used "iterator invalidation" because it is an established term.
- Walter Bright (3/13) Apr 10 2015 This would be a bad design of an RCO. RCO's must be constructed to not a...
- Martin Nowak (2/4) Apr 11 2015 And taking the address of that is already unsafe.
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (3/8) Apr 11 2015 It isn't under my proposal, which Walter has already accepted the
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (7/17) Apr 11 2015 There is no reason for this restriction. But if this is your
- Walter Bright (5/21) Apr 11 2015 In your example posted upthread, it wasn't safe. Perhaps scoped pointers...
- Martin Nowak (17/18) Apr 10 2015 In the first problem example:
- Walter Bright (2/20) Apr 10 2015 The latter.
- Michel Fortin (19/47) Apr 10 2015 And how is it pinned in this case?
- weaselcat (4/53) Apr 10 2015 AFAICT it would create a temporary copy of s.array, which would
- Walter Bright (2/16) Apr 10 2015
- Martin Nowak (3/5) Apr 10 2015 Can you update that part in the DIP, it wasn't clear that the temporary
- deadalnix (4/10) Apr 10 2015 If a struct has RCO fields, shouldn't it be an RCO itself, and as
- Michel Fortin (12/23) Apr 10 2015 Not necessarily. A @disabled postblit could make it no longer RCO
- Walter Bright (2/7) Apr 10 2015 It pins RCO objects, however they are derived.
- Martin Nowak (9/10) Apr 11 2015 It's a very interesting proposal to tackle this specific problem.
On Wednesday, 8 April 2015 at 23:11:08 UTC, Walter Bright wrote:http://wiki.dlang.org/DIP77Deceptively simple solution for a hard problem.
Apr 08 2015
On Wednesday, 8 April 2015 at 23:11:08 UTC, Walter Bright wrote:http://wiki.dlang.org/DIP77That is pretty much the old Rust solution called boxing. This sound like the right way forward to me.
Apr 08 2015
On 4/8/2015 5:30 PM, deadalnix wrote:On Wednesday, 8 April 2015 at 23:11:08 UTC, Walter Bright wrote:Yes, it's equivalent to it. I had started with doing an INC/DEC pair, but that implied adding more logic to detect how to do an INC/DEC for a particular type. The logic for doing a copy is much more straightforward. The RC object should also be designed in such a way that the copy is not costly. Function purity is again showing what an advantage it is. Andrei's idea was to not do the copy for system opAssign's, thus providing C++ equivalence for those folks that need it and don't care about guaranteed memory safety.http://wiki.dlang.org/DIP77That is pretty much the old Rust solution called boxing. This sound like the right way forward to me.
Apr 08 2015
On Thursday, 9 April 2015 at 00:30:46 UTC, deadalnix wrote:On Wednesday, 8 April 2015 at 23:11:08 UTC, Walter Bright wrote:Any idea why they abandoned it?http://wiki.dlang.org/DIP77That is pretty much the old Rust solution called boxing. This sound like the right way forward to me.
Apr 08 2015
On 4/8/2015 6:19 PM, Brad Anderson wrote:On Thursday, 9 April 2015 at 00:30:46 UTC, deadalnix wrote:No, but I can guess. It's less efficient.On Wednesday, 8 April 2015 at 23:11:08 UTC, Walter Bright wrote:Any idea why they abandoned it?http://wiki.dlang.org/DIP77That is pretty much the old Rust solution called boxing. This sound like the right way forward to me.
Apr 08 2015
On Thursday, 9 April 2015 at 01:35:14 UTC, Walter Bright wrote:On 4/8/2015 6:19 PM, Brad Anderson wrote:This and the fact that they want to prevent multiple writable burrow for concurrency reasons, so that seemed like the correct way forward for them.On Thursday, 9 April 2015 at 00:30:46 UTC, deadalnix wrote:No, but I can guess. It's less efficient.On Wednesday, 8 April 2015 at 23:11:08 UTC, Walter Bright wrote:Any idea why they abandoned it?http://wiki.dlang.org/DIP77That is pretty much the old Rust solution called boxing. This sound like the right way forward to me.
Apr 08 2015
On Wednesday, 8 April 2015 at 23:11:08 UTC, Walter Bright wrote:http://wiki.dlang.org/DIP77Can this be clarified a little?The lifetime of tmp will be the same as that of a temporary with a destructor.Does that mean the lifetime of tmp is tied to the scope of the function being called, or the current scope calling the function?
Apr 08 2015
On 4/8/2015 5:49 PM, weaselcat wrote:On Wednesday, 8 April 2015 at 23:11:08 UTC, Walter Bright wrote:The same as that of a tmp being returned from a function - to the end of the expression.http://wiki.dlang.org/DIP77Can this be clarified a little?The lifetime of tmp will be the same as that of a temporary with a destructor.Does that mean the lifetime of tmp is tied to the scope of the function being called, or the current scope calling the function?
Apr 08 2015
On Thursday, 9 April 2015 at 01:35:54 UTC, Walter Bright wrote:The same as that of a tmp being returned from a function - to the end of the expression.But how will this work with anything that makes RCArrays reachable through indirections...? Is the compiler going to do a recursive scan and create temporaries of all RC-pointers that are reachable? (e.g. RCArrays of RCArrays)
Apr 09 2015
On 4/9/2015 12:58 PM, "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= <ola.fosheim.grostad+dlang gmail.com>" wrote:On Thursday, 9 April 2015 at 01:35:54 UTC, Walter Bright wrote:It examines the types of all mutable values available to the function. Note the discussion of the effect of purity in the DIP.The same as that of a tmp being returned from a function - to the end of the expression.But how will this work with anything that makes RCArrays reachable through indirections...? Is the compiler going to do a recursive scan and create temporaries of all RC-pointers that are reachable? (e.g. RCArrays of RCArrays)
Apr 09 2015
On Thursday, 9 April 2015 at 21:47:47 UTC, Walter Bright wrote:On 4/9/2015 12:58 PM, "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?=So if I pass in a graph, linked list or a tree, then it will scan the entire structure at runtime and build a large set of temporaries before calling the function?indirections...? Is the compiler going to do a recursive scan and create temporaries of all RC-pointers that are reachable? (e.g. RCArrays of RCArrays)It examines the types of all mutable values available to the function.
Apr 09 2015
On Friday, 10 April 2015 at 05:56:40 UTC, Ola Fosheim Grøstad wrote:On Thursday, 9 April 2015 at 21:47:47 UTC, Walter Bright wrote:No, but indeed, passing down indirection require boxing too. The DIP is not clear about it.On 4/9/2015 12:58 PM, "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?=So if I pass in a graph, linked list or a tree, then it will scan the entire structure at runtime and build a large set of temporaries before calling the function?indirections...? Is the compiler going to do a recursive scan and create temporaries of all RC-pointers that are reachable? (e.g. RCArrays of RCArrays)It examines the types of all mutable values available to the function.
Apr 09 2015
On Friday, 10 April 2015 at 06:02:35 UTC, deadalnix wrote:No, but indeed, passing down indirection require boxing too. The DIP is not clear about it.Not sure what you mean by boxing. Usually it means that you wrap a value type in an object to turn it into a reference type. In Rust I think it means the same as unique_ptr ( http://rustbyexample.com/box.html ). How will DIP77 work out if you represent a directed acyclic graph with ref counted edges? (e.g. one RCArray per node) Basically the problem that needs to be solved is very close to determining if there is no aliasing between parameters. The compile time solution could be either whole program pointer analysis or heavy type constraints (linear typing). A general runtime solution would be rather inefficient IMO. I think memory safety in D probably could be better solved, and with less effort, by a separate tool if DMD could be made to generate high level IR (a D VM that preserves high level information better than say LLVM).
Apr 10 2015
On 4/9/2015 10:56 PM, "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= <ola.fosheim.grostad+dlang gmail.com>" wrote:So if I pass in a graph, linked list or a tree, then it will scan the entire structure at runtime and build a large set of temporaries before calling the function?Nope. It'll scan at compile time the types reachable through the parameters. If any of those types are RCO's that have a type that matches a ref parameter, the ref parameter's RCO will get copied.
Apr 10 2015
On Friday, 10 April 2015 at 07:01:47 UTC, Walter Bright wrote:Nope. It'll scan at compile time the types reachable through the parameters. If any of those types are RCO's that have a type that matches a ref parameter, the ref parameter's RCO will get copied.But how can this work? If I provide 2 ref parameters to different Node instances (not a RCO) in the same graph. How can I then be sure that it will not disappear? E.g. ref1 -> Node->RCRef->Edge(RCO)->Node->RCRef->Edge(RCO)->Node"X" ref2 -> Node"X"
Apr 10 2015
On 4/10/2015 12:10 AM, "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= <ola.fosheim.grostad+dlang gmail.com>" wrote:On Friday, 10 April 2015 at 07:01:47 UTC, Walter Bright wrote:Because with two parameters, if one is a ref coming from an RCO rc1, and the other is a ref to a type that is the root of a graph that contains an RCO type, then the rc1 is copied.Nope. It'll scan at compile time the types reachable through the parameters. If any of those types are RCO's that have a type that matches a ref parameter, the ref parameter's RCO will get copied.But how can this work? If I provide 2 ref parameters to different Node instances (not a RCO) in the same graph. How can I then be sure that it will not disappear? E.g. ref1 -> Node->RCRef->Edge(RCO)->Node->RCRef->Edge(RCO)->Node"X" ref2 -> Node"X"
Apr 10 2015
On Friday, 10 April 2015 at 08:47:09 UTC, Walter Bright wrote:On 4/10/2015 12:10 AM, "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?=ref1 -> RCO1 -> N1 -> RCRef1 -> RCO2 -> N2 -> RCRef3 -> RCO3 -> N3 ref2 -> N3 N1..N3 represent resources (like a file). process(ref1,ref2){ ref1.stuff.stuff.stuff.release(); // Node2 and Node3 is released. ref2.read(); // fails/garbage }ref1 -> Node->RCRef->Edge(RCO)->Node->RCRef->Edge(RCO)->Node"X" ref2 -> Node"X"Because with two parameters, if one is a ref coming from an RCO rc1, and the other is a ref to a type that is the root of a graph that contains an RCO type, then the rc1 is copied.
Apr 10 2015
On 4/10/2015 2:14 AM, "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= <ola.fosheim.grostad+dlang gmail.com>" wrote:On Friday, 10 April 2015 at 08:47:09 UTC, Walter Bright wrote:ref2 is copied.On 4/10/2015 12:10 AM, "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?=ref1 -> RCO1 -> N1 -> RCRef1 -> RCO2 -> N2 -> RCRef3 -> RCO3 -> N3 ref2 -> N3 N1..N3 represent resources (like a file). process(ref1,ref2){ ref1.stuff.stuff.stuff.release(); // Node2 and Node3 is released. ref2.read(); // fails/garbage }ref1 -> Node->RCRef->Edge(RCO)->Node->RCRef->Edge(RCO)->Node"X" ref2 -> Node"X"Because with two parameters, if one is a ref coming from an RCO rc1, and the other is a ref to a type that is the root of a graph that contains an RCO type, then the rc1 is copied.
Apr 10 2015
On Friday, 10 April 2015 at 09:15:11 UTC, Walter Bright wrote:ref2 is copied.You cannot copy a resource like a memfile. It is already closed and the memory is gone.
Apr 10 2015
On 4/10/2015 2:27 AM, "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= <ola.fosheim.grostad+dlang gmail.com>" wrote:On Friday, 10 April 2015 at 09:15:11 UTC, Walter Bright wrote:Please read the DIP again. The copy happens earlier.ref2 is copied.You cannot copy a resource like a memfile. It is already closed and the memory is gone.
Apr 10 2015
On Friday, 10 April 2015 at 09:28:57 UTC, Walter Bright wrote:Please read the DIP again. The copy happens earlier.But one cannot keep a stateful resource alive by copying memory. One would have to take ownership to keep it alive. In order to do that you need a model for ownership.
Apr 10 2015
On 4/10/2015 2:54 AM, "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= <ola.fosheim.grostad+dlang gmail.com>" wrote:On Friday, 10 April 2015 at 09:28:57 UTC, Walter Bright wrote:That's what ref counting is about.Please read the DIP again. The copy happens earlier.But one cannot keep a stateful resource alive by copying memory. One would have to take ownership to keep it alive. In order to do that you need a model for ownership.
Apr 10 2015
On Friday, 10 April 2015 at 10:28:03 UTC, Walter Bright wrote:That's what ref counting is about.That would require pervasive ref-counting.
Apr 10 2015
Am Fri, 10 Apr 2015 14:04:39 +0000 schrieb "Ola Fosheim Gr=C3=B8stad" <ola.fosheim.grostad+dlang gmail.com>:On Friday, 10 April 2015 at 10:28:03 UTC, Walter Bright wrote:You make is sound like there was an alternative to ref counting for resources. Is there? --=20 MarcoThat's what ref counting is about.=20 That would require pervasive ref-counting.
Apr 11 2015
On Saturday, 11 April 2015 at 18:20:51 UTC, Marco Leise wrote:Am Fri, 10 Apr 2015 14:04:39 +0000 schrieb "Ola Fosheim Grøstad" <ola.fosheim.grostad+dlang gmail.com>:Ownership, GC.On Friday, 10 April 2015 at 10:28:03 UTC, Walter Bright wrote:You make is sound like there was an alternative to ref counting for resources. Is there?That's what ref counting is about.That would require pervasive ref-counting.
Apr 11 2015
Am Sat, 11 Apr 2015 20:42:52 +0000 schrieb "deadalnix" <deadalnix gmail.com>:On Saturday, 11 April 2015 at 18:20:51 UTC, Marco Leise wrote:That doesn't convince me yet. GC is just incorrect to use here. D's GC like any other that is non-deterministic will hold on to many external resources for longer than is feasible. (Unique) ownership on the other hand isn't really what we are looking at here, right? I mean, the DIP talks about what happens when you are dealing with multiple references to the same item. That leaves us with RC, which I think is a good choice. --=20 MarcoAm Fri, 10 Apr 2015 14:04:39 +0000 schrieb "Ola Fosheim Gr=C3=B8stad" <ola.fosheim.grostad+dlang gmail.com>:=20 Ownership, GC.On Friday, 10 April 2015 at 10:28:03 UTC, Walter Bright wrote:You make is sound like there was an alternative to ref counting for resources. Is there?That's what ref counting is about.=20 That would require pervasive ref-counting.
May 01 2015
On Wednesday, 8 April 2015 at 23:11:08 UTC, Walter Bright wrote:http://wiki.dlang.org/DIP77I've only skimmed this, but: 1. I don't think Objective-C uses autorelease pools for any other reason than to make manual ref counting easier. See also John McCall's reflections on ARC: http://forum.dlang.org/thread/mcqcor$aa$1 digitalmars.com?page=2#post-hgmhgirfervrsvcghchw:40forum.dlang.org 2. How will this work with "yield"? Why not just implement the more generic solution (shared pointers with move/borrow or WPO) ?
Apr 09 2015
On Thursday, 9 April 2015 at 09:05:10 UTC, Ola Fosheim Grøstad wrote:2. How will this work with "yield"?You yield both caller and callee, so you'll get caller's boxing in the yield.Why not just implement the more generic solution (shared pointers with move/borrow or WPO) ?I don't think this is possible.
Apr 09 2015
On Thursday, 9 April 2015 at 18:31:24 UTC, deadalnix wrote:On Thursday, 9 April 2015 at 09:05:10 UTC, Ola Fosheim Grøstad wrote:But the coroutine stack and everything on it will be intact when it yields, including references to array elements...?2. How will this work with "yield"?You yield both caller and callee, so you'll get caller's boxing in the yield.It should be possible with pointer analysis, but the easier approach is just to ban non-const ref parameters (c++ style) for rc-pointer-objects, so maybe D should provide "head const" after all...Why not just implement the more generic solution (shared pointers with move/borrow or WPO) ?I don't think this is possible.
Apr 09 2015
On 2015-04-08 23:10:37 +0000, Walter Bright <newshound2 digitalmars.com> said:http://wiki.dlang.org/DIP77In the definition of a Reference Counted Object: """ An object is assumed to be reference counted if it has a postblit and a destructor, and does not have an opAssign marked system. """ Why should it not have an opAssign marked system? And what happens if the struct has a postblit but it is disabled? Will the compiler forbid you from passing it by ref in cases where it'd need to make a copy, or will it just not be a RCO? More generally, is it right to add implicit copying just because a struct has a postblit and a destructor? If someone implemented a by-value container in D (such as those found in C++), this behaviour of the compiler would trash the performance by silently doing useless unnecessary copies. You won't even get memory-safety as a benefit: if the container allocates from the GC it's safe anyway, otherwise you're referencing deallocated memory with your ref parameter (copying the struct would just make a copy elsewhere, not retain the memory of the original). I think you're assuming too much from the presence of a postblit and a destructor. This implicit copy behaviour should not be trigged by seemingly unrelated clues. Instead of doing that: auto tmp = rc; the compiler should insert this: auto tmp = rc.opPin(); RCArray can implement opPin by returning a copy of itself. A by-value container can implement opPin by returning a dummy struct that retains the container's memory until the dummy struct's destructor is called. Alternatively someone could make a dummy "void opPin() system {}" to signal it isn't safe to pass internal references around (only in system code would the implicit call to opPin compile). If you were writing a layout-compatible D version of std::vector, you'd likely have to use a system opPin because there's no way you can "pin" that memory and guaranty memory-safety when passing references around. -- Michel Fortin michel.fortin michelf.ca http://michelf.ca
Apr 09 2015
On 4/9/2015 5:05 AM, Michel Fortin wrote:Why should it not have an opAssign marked system?"Andrei's idea was to not do the copy for system opAssign's, thus providing C++ equivalence for those folks that need it and don't care about guaranteed memory safety."And what happens if the struct has a postblit but it is disabled? Will the compiler forbid you from passing it by ref in cases where it'd need to make a copy, or will it just not be a RCO?It wouldn't be an RCO.More generally, is it right to add implicit copying just because a struct has a postblit and a destructor? If someone implemented a by-value container in D (such as those found in C++), this behaviour of the compiler would trash the performance by silently doing useless unnecessary copies. You won't even get memory-safety as a benefit: if the container allocates from the GC it's safe anyway, otherwise you're referencing deallocated memory with your ref parameter (copying the struct would just make a copy elsewhere, not retain the memory of the original).The only real purpose to a postblit is to support ref counting. Why would a by-value container use a postblit and not ref count?I think you're assuming too much from the presence of a postblit and a destructor. This implicit copy behaviour should not be trigged by seemingly unrelated clues. Instead of doing that: auto tmp = rc; the compiler should insert this: auto tmp = rc.opPin(); RCArray can implement opPin by returning a copy of itself. A by-value container can implement opPin by returning a dummy struct that retains the container's memory until the dummy struct's destructor is called. Alternatively someone could make a dummy "void opPin() system {}" to signal it isn't safe to pass internal references around (only in system code would the implicit call to opPin compile). If you were writing a layout-compatible D version of std::vector, you'd likely have to use a system opPin because there's no way you can "pin" that memory and guaranty memory-safety when passing references around.My first impression is that's too complicated for the user to get right.
Apr 09 2015
On Thursday, 9 April 2015 at 18:44:10 UTC, Walter Bright wrote:The only real purpose to a postblit is to support ref counting. Why would a by-value container use a postblit and not ref count?A struct could have a postblit defined if you are implementing something like std::vector, where you you copy the memory when the struct is copied. I'm not sure why you would want to do such a thing in D, though. If allocating memory is your concern, you probably don't want any allocation, including malloc.
Apr 09 2015
On 4/9/2015 11:53 AM, w0rp wrote:On Thursday, 9 April 2015 at 18:44:10 UTC, Walter Bright wrote:I'm not sure why you'd do that, either. Just make the memory part ref counted, then when modifying it, make the copy then if your ref count > 1. If you want to interface with std::vector, make opAssign system, after all, you're dealing with C++ :-)The only real purpose to a postblit is to support ref counting. Why would a by-value container use a postblit and not ref count?A struct could have a postblit defined if you are implementing something like std::vector, where you you copy the memory when the struct is copied. I'm not sure why you would want to do such a thing in D, though.
Apr 09 2015
On Thursday, 9 April 2015 at 18:44:10 UTC, Walter Bright wrote:On 4/9/2015 5:05 AM, Michel Fortin wrote:Why not bind this behavior to extern(C++) ?Why should it not have an opAssign marked system?"Andrei's idea was to not do the copy for system opAssign's, thus providing C++ equivalence for those folks that need it and don't care about guaranteed memory safety."The only real purpose to a postblit is to support ref counting. Why would a by-value container use a postblit and not ref count?In C++, the only real purpose of template were generic containers, and that didn't ended up well. It is dangerous, at language level, to reason from usage instead of first principle (not that usage do not matter, usage should serve as a guideline for the principles) or thing like C++ templates happens.My first impression is that's too complicated for the user to get right.Yeah, I don't think opPin is a the right way to go. It is always easy and tempting to add new stuff to make X or Y work, but at the end, it only create language complexity explosion. There are some inefficiencies involved here, but I trust the compiler to be able to optimize it away for the most part, and we have a backdoor for thoses who want to bypass safety. More generally, this is why I oppose the return attribute + adding op on reference type in favor of a principle scope proposal. The first one is 2 language features for a less general end result.
Apr 09 2015
On 4/9/2015 1:21 PM, deadalnix wrote:On Thursday, 9 April 2015 at 18:44:10 UTC, Walter Bright wrote:Because the charter of system is "the user supplies the memory safety", which fits here perfectly. extern(C++) carries a lot of other stuff with it.On 4/9/2015 5:05 AM, Michel Fortin wrote:Why not bind this behavior to extern(C++) ?Why should it not have an opAssign marked system?"Andrei's idea was to not do the copy for system opAssign's, thus providing C++ equivalence for those folks that need it and don't care about guaranteed memory safety."It is dangerous, at language level, to reason from usage instead of first principle (not that usage do not matter, usage should serve as a guideline for the principles) or thing like C++ templates happens.On the other hand, throwing things in the language just because you can, with no idea what they are good for or how they will be used, doesn't end well.Glad you agree. I'm afraid of making something that is technically correct, but unusable.My first impression is that's too complicated for the user to get right.Yeah, I don't think opPin is a the right way to go. It is always easy and tempting to add new stuff to make X or Y work, but at the end, it only create language complexity explosion.There are some inefficiencies involved here, but I trust the compiler to be able to optimize it away for the most part, and we have a backdoor for thoses who want to bypass safety.Yes. Interestingly, this is a superset of what Rust does. Rust's has the idea of only one mutable reference at a time, for efficiency. As the DIP points out, if the function only has const references available other than the one mutable one, it doesn't do the copy, either. I was curious how Rust handled the global variable issue. Turns out it doesn't - mutable global variables are marked as "unsafe" and the checker gives up on it.More generally, this is why I oppose the return attribute + adding op on reference type in favor of a principle scope proposal. The first one is 2 language features for a less general end result.I understand where you're coming from on this. The design was picked for being as simple as possible with the least disruption.
Apr 09 2015
On Thursday, 9 April 2015 at 22:06:01 UTC, Walter Bright wrote:I was curious how Rust handled the global variable issue. Turns out it doesn't - mutable global variables are marked as "unsafe" and the checker gives up on it.I think it's safe to say that if even Rust with its linear type system and advanced borrow checker cannot deal with it, noone can, short of whole program analysis. And it's easy to understand why once you realize that it's all about aliasing. That's why I also suggest to make borrowing from mutable globals unsafe.
Apr 10 2015
On 2015-04-09 18:43:25 +0000, Walter Bright <newshound2 digitalmars.com> said:The only real purpose to a postblit is to support ref counting. Why would a by-value container use a postblit and not ref count?Because reference counting has tradoffs, or because someone translates an exiting C++ program and want to keep the semantics the same to make the translation simpler. If you want to limit postblit to the reference counting use case I guess that's fine, although this limitation should probably be clarified somewhere because to someone with a C++ background it looks a lot like a substitute for a copy-constructor. But this goes beyond containers. Destructors and postblits are implicitly created whenever a field contained within a struct has them. So you could have this: struct Big { RCArray!T array; int[1000] ints; } and now implicit copies of Big are made because Big implicitly gained a destructor and postblit from its array field. But at least you gain memory safety. ...or maybe not. Let's add another field to Big: struct Handle { // shouldn't be able to make copies of this disable this(this) {} } struct Big { RCArray!T array; int[1000] ints; Handle handle; } Now Big's implicit postblit becomes disabled too (because Handle can't handle copying), therefore it is no longer a RCO object and the compiler will no longer create temporary copies. Now you've trashed memory-safety. To be fair, my opPin idea suffers a similar fate here: there is no opPin defined for Big, which creates a hole in memory-safety. To compensate, the compiler would have to call opPin individually for each field that defines it. -- Michel Fortin michel.fortin michelf.ca http://michelf.ca
Apr 10 2015
On 4/10/2015 4:49 AM, Michel Fortin wrote:...or maybe not. Let's add another field to Big: struct Handle { // shouldn't be able to make copies of this disable this(this) {} } struct Big { RCArray!T array; int[1000] ints; Handle handle; } Now Big's implicit postblit becomes disabled too (because Handle can't handle copying), therefore it is no longer a RCO object and the compiler will no longer create temporary copies. Now you've trashed memory-safety.The copy would be made of array, not Big.
Apr 10 2015
On Thursday, 9 April 2015 at 12:05:16 UTC, Michel Fortin wrote:""" An object is assumed to be reference counted if it has a postblit and a destructor, and does not have an opAssign marked system. """It seems to only fit to RCO, I'm not positive though. We should formalize this, by documenting it and by adding isRCO traits to phobos.
Apr 10 2015
On Wednesday, 8 April 2015 at 23:11:08 UTC, Walter Bright wrote:http://wiki.dlang.org/DIP77From the DIP: T foo(ref Payload payload); ... RC rc; foo(rc.payload); rewrite foo(rc) as: auto tmp = rc; foo(rc.payload); The only question I had was whether there was an advantage to rewriting the statement in its own scope: { auto tmp = rc; foo(rc.payload); } You can save some stack space that way, but I don't know how hard it is to implement.
Apr 09 2015
http://wiki.dlang.org/DIP77We seem to be incrementally edging towards Rust's memory management system or something similar and retracing their steps along the path to get there. Hypothetically how close could we get to being able to opt into a Rust world from the GC world or C worlds of memory management?
Apr 10 2015
On Friday, 10 April 2015 at 09:16:38 UTC, ixid wrote:extern(Rust) embraceExtendExtinguish();http://wiki.dlang.org/DIP77We seem to be incrementally edging towards Rust's memory management system or something similar and retracing their steps along the path to get there. Hypothetically how close could we get to being able to opt into a Rust world from the GC world or C worlds of memory management?
Apr 10 2015
On 4/10/2015 2:16 AM, ixid wrote:As I explained to deadalnix in this thread, D's semantics in this regard are a superset of Rust's.http://wiki.dlang.org/DIP77We seem to be incrementally edging towards Rust's memory management system or something similar and retracing their steps along the path to get there. Hypothetically how close could we get to being able to opt into a Rust world from the GC world or C worlds of memory management?
Apr 10 2015
On 4/10/15 2:16 AM, ixid wrote:We hope to do better than Rust. -- Andreihttp://wiki.dlang.org/DIP77We seem to be incrementally edging towards Rust's memory management system or something similar and retracing their steps along the path to get there. Hypothetically how close could we get to being able to opt into a Rust world from the GC world or C worlds of memory management?
Apr 10 2015
On Friday, 10 April 2015 at 15:44:32 UTC, Andrei Alexandrescu wrote:We hope to do better than Rust. -- AndreiHope does not cut it. A design that breaks down even on a linked list (e.g. you have to turn to ref-counted pointers everywhere) and that makes findByRef(container,node) break should not have made it to a DIP in the first place. D needs clean semantics on what is a value. The only sensible definition for a copyable value is that you cannot take the identity in _any way_ from a value or anything that can be reached from it. D needs clean semantics on what is unique ownership. Ref counting is not it. Pervasive ref counting requires WPO to work out ok. C++14 with sanitizer tooling is a lot more attractive than this direction you are going for.
Apr 11 2015
I was thinking about this again, and how the first 'ref' would create a copy in order to keep the object around. At first I thought I didn't like that, but then I realised that it's actually not far from what I wanted for taking r-values by reference. I commonly write functions which take values either by reference or by value in this way. void foo(ref T value); void foo(T value) { foo(value); } Which obviously results in a combinatorial explosion of overloads, which you can write automatically some times with 'auto ref'. My question is, in the greater context of the language, supposing we had this copying behaviour for a first ref for reference counted objects, will it putting something in the language for copying r-values into functions, or will it provide a path to implement such a thing?
Apr 11 2015
On Saturday, 11 April 2015 at 08:35:18 UTC, Ola Fosheim Grøstad wrote:On Friday, 10 April 2015 at 15:44:32 UTC, Andrei Alexandrescu wrote:a bidirectional linked list cannot be implemented in safe rust afaikWe hope to do better than Rust. -- AndreiHope does not cut it. A design that breaks down even on a linked list (e.g. you have to turn to ref-counted pointers everywhere) and that makes findByRef(container,node) break should not have made it to a DIP in the first place.
Apr 11 2015
On Wednesday, 8 April 2015 at 23:11:08 UTC, Walter Bright wrote:http://wiki.dlang.org/DIP77So someone passes an RCO via ref to avoid the inc/dec, and because that imposes safety issues we turn it into some sort of pass by value under the hood, defeating the purpose, and provide an opt-out via system opAssign. Wouldn't it more straightforward to make pass-by-ref unsafe ( system) for RCOs? Then the only thing missing to make this equally powerful, would be an optimization opportunity for the compiler to elide copies of pass-by-value RCOs, e.g. it could avoid calling the postblit when the function retains the refcount.
Apr 10 2015
On 4/10/2015 3:02 AM, Martin Nowak wrote:On Wednesday, 8 April 2015 at 23:11:08 UTC, Walter Bright wrote:Or you could pass it by const ref (which is what Rust essentially does).http://wiki.dlang.org/DIP77So someone passes an RCO via ref to avoid the inc/dec, and because that imposes safety issues we turn it into some sort of pass by value under the hood, defeating the purpose, and provide an opt-out via system opAssign.Wouldn't it more straightforward to make pass-by-ref unsafe ( system) for RCOs?That's what we have now. It's not good enough.
Apr 10 2015
On 04/10/2015 12:29 PM, Walter Bright wrote:Maybe I'm missing something, but this proposal seems to make `ref RCO` fairly useless, because it creates a copy anyhow.So someone passes an RCO via ref to avoid the inc/dec, and because that imposes safety issues we turn it into some sort of pass by value under the hood, defeating the purpose, and provide an opt-out via system opAssign.Or you could pass it by const ref (which is what Rust essentially does).Assigning a RefCounted is marked system, pass-by-ref is safe. What's missing, you want to be able to use RefCounted in safe code? Why not pass it by value then? That would pin the object and you could elide the additional inc/dec just like you propose to elide the temporary copies. It's more efficient to pass a smart pointer like RefCounted by-value anyhow.Wouldn't it more straightforward to make pass-by-ref unsafe ( system) for RCOs?That's what we have now. It's not good enough.
Apr 10 2015
On 4/10/2015 2:20 PM, Martin Nowak wrote:On 04/10/2015 12:29 PM, Walter Bright wrote:Not if you read the copy elision section.Maybe I'm missing something, but this proposal seems to make `ref RCO` fairly useless, because it creates a copy anyhow.So someone passes an RCO via ref to avoid the inc/dec, and because that imposes safety issues we turn it into some sort of pass by value under the hood, defeating the purpose, and provide an opt-out via system opAssign.Or you could pass it by const ref (which is what Rust essentially does).Assigning a RefCounted is marked system,That's kind of throwing in the towel, isn't it?pass-by-ref is safe. What's missing, you want to be able to use RefCounted in safe code? Why not pass it by value then? That would pin the object and you could elide the additional inc/dec just like you propose to elide the temporary copies. It's more efficient to pass a smart pointer like RefCounted by-value anyhow.
Apr 10 2015
On Friday, 10 April 2015 at 21:20:32 UTC, Martin Nowak wrote:Assigning a RefCounted is marked system, pass-by-ref is safe. What's missing, you want to be able to use RefCounted in safe code? Why not pass it by value then?This actually sounds quite logical to me - passing an RC object by ref doesn't sound very safe to begin with.
Apr 10 2015
On Friday, 10 April 2015 at 10:02:01 UTC, Martin Nowak wrote:On Wednesday, 8 April 2015 at 23:11:08 UTC, Walter Bright wrote:Only the first pass by ref create a copy. You can then pass the ref down all you want without copy. That is an acceptable cost IMO.http://wiki.dlang.org/DIP77So someone passes an RCO via ref to avoid the inc/dec, and because that imposes safety issues we turn it into some sort of pass by value under the hood, defeating the purpose, and provide an opt-out via system opAssign. Wouldn't it more straightforward to make pass-by-ref unsafe ( system) for RCOs? Then the only thing missing to make this equally powerful, would be an optimization opportunity for the compiler to elide copies of pass-by-value RCOs, e.g. it could avoid calling the postblit when the function retains the refcount.
Apr 10 2015
On Friday, 10 April 2015 at 23:12:55 UTC, deadalnix wrote:On Friday, 10 April 2015 at 10:02:01 UTC, Martin Nowak wrote:It's not acceptable that it happens behind the user's back. Costly operations must be explicit.On Wednesday, 8 April 2015 at 23:11:08 UTC, Walter Bright wrote:Only the first pass by ref create a copy. You can then pass the ref down all you want without copy. That is an acceptable cost IMO.http://wiki.dlang.org/DIP77So someone passes an RCO via ref to avoid the inc/dec, and because that imposes safety issues we turn it into some sort of pass by value under the hood, defeating the purpose, and provide an opt-out via system opAssign. Wouldn't it more straightforward to make pass-by-ref unsafe ( system) for RCOs? Then the only thing missing to make this equally powerful, would be an optimization opportunity for the compiler to elide copies of pass-by-value RCOs, e.g. it could avoid calling the postblit when the function retains the refcount.
Apr 11 2015
On 4/11/2015 2:28 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net>" wrote:It's not acceptable that it happens behind the user's back. Costly operations must be explicit.Don't know of a better solution.
Apr 11 2015
On Saturday, 11 April 2015 at 09:41:07 UTC, Walter Bright wrote:On 4/11/2015 2:28 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net>" wrote:How about this? Btw, I also made other changes: No implied scope for safe functions, no overloading on scope (instead postblit and destructor are skipped), and added a terminology section (rather important!).It's not acceptable that it happens behind the user's back. Costly operations must be explicit.Don't know of a better solution.
Apr 11 2015
On Saturday, 11 April 2015 at 11:33:51 UTC, Marc Schütz wrote:On Saturday, 11 April 2015 at 09:41:07 UTC, Walter Bright wrote:Just passing, a bit off topic and clearly not familiar enough with the discussed subject but in case you missed it the last rust blog post is an nice and motivated introduction to their ownership system : http://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html I need to read about Marc's scope proposal...I am not convinced by the dip77, what about raii managed classes with costly opAssign operator (like in w0rn example) ? The goal of passing an object by reference is to avoid the copy and here you guess the parameter is ref-counted and made a (pseudo-)copy ? Then any allocating opAssign should be marked system ?On 4/11/2015 2:28 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net>" wrote:How about this? Btw, I also made other changes: No implied scope for safe functions, no overloading on scope (instead postblit and destructor are skipped), and added a terminology section (rather important!).It's not acceptable that it happens behind the user's back. Costly operations must be explicit.Don't know of a better solution.
Apr 11 2015
On 4/11/15 5:35 AM, matovitch wrote:I am not convinced by the dip77, what about raii managed classes with costly opAssign operator (like in w0rn example) ? The goal of passing an object by reference is to avoid the copy and here you guess the parameter is ref-counted and made a (pseudo-)copy ? Then any allocating opAssign should be marked system ?Expensive opAssign or expensive postblit? -- Andrei
Apr 11 2015
On Sunday, 12 April 2015 at 04:18:54 UTC, Andrei Alexandrescu wrote:On 4/11/15 5:35 AM, matovitch wrote:Well both in the example given by w0rp. I guess D as no "rule of five" but still a "rule of three" (which is in fact rule of four with the copy-and-swap idiom) about coding posblit, opAssign and destructor together ?I am not convinced by the dip77, what about raii managed classes with costly opAssign operator (like in w0rn example) ? The goal of passing an object by reference is to avoid the copy and here you guess the parameter is ref-counted and made a (pseudo-)copy ? Then any allocating opAssign should be marked system ?Expensive opAssign or expensive postblit? -- Andrei
Apr 12 2015
On 4/11/2015 4:33 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net>" wrote:On Saturday, 11 April 2015 at 09:41:07 UTC, Walter Bright wrote:A quick read of this suggests it is doing the Rust model of only one mutable reference at a time. Is this really viable with D?On 4/11/2015 2:28 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net>" wrote:How about this? Btw, I also made other changes: No implied scope for safe functions, no overloading on scope (instead postblit and destructor are skipped), and added a terminology section (rather important!).It's not acceptable that it happens behind the user's back. Costly operations must be explicit.Don't know of a better solution.
Apr 12 2015
On Sunday, 12 April 2015 at 07:17:07 UTC, Walter Bright wrote:A quick read of this suggests it is doing the Rust model of only one mutable reference at a time. Is this really viable with D?I would love to see a storage class to add the rust ownership model to D. I surely don't know if it's feasible.
Apr 12 2015
On Sunday, 12 April 2015 at 07:17:07 UTC, Walter Bright wrote:On 4/11/2015 4:33 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net>" wrote:I think it is. You have to keep in mind that this is opt-in; it only applies to `scope` variables. I would agree that as a default, it wouldn't fit D at all. I think that, for all its usefulness, it'd be a tad too limiting for my taste if I were forced to use it everywhere. In Rust, it needs to be ubiquitous, because their goal is to get by without a GC. We on the other hand just want a way to make the GC easier to avoid. We also want to be able to use these different programming styles side by side, therefore an opt-in solution is good. Besides, I too want to recommend the article Matovitch linked to, and Yehuda Katz' article mentioned therein, because they make a good point demonstrating that it gives more correctness guarantees than just memory safety: http://forum.dlang.org/post/ttjzihuffrdlgqonqiwi forum.dlang.org It's a great building block for lots of nice things. In fact, it's quite likely the only way to get these guarantees once you look beyond reference counting.A quick read of this suggests it is doing the Rust model of only one mutable reference at a time. Is this really viable with D?
Apr 12 2015
Marc Schütz:You have to keep in mind that this is opt-in; it only applies to `scope` variables. I would agree that as a default, it wouldn't fit D at all. I think that, for all its usefulness, it'd be a tad too limiting for my taste if I were forced to use it everywhere.I think D Zen asks for safety on default and opt-out on request. See also " safe by default": https://issues.dlang.org/show_bug.cgi?id=13838 Bye, bearophile
Apr 12 2015
On Sunday, 12 April 2015 at 12:06:50 UTC, bearophile wrote:I think D Zen asks for safety on default and opt-out on request.Marc talked about unique ownership vs. shared ownership, not about safe vs. unsafe.
Apr 12 2015
On Sunday, 12 April 2015 at 07:17:07 UTC, Walter Bright wrote:On 4/11/2015 4:33 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net>" wrote:It's a very good ownership model IMO, because it has no runtime overhead and often sharing/escaping isn't needed. Would at least be interesting to explore this in more detail for scoped variables. As a side note, I find that unique ownership is strangely missing from our discussions, yet it's a perfect ownership model for resources such as a File. https://github.com/D-Programming-Language/phobos/pull/3171On Saturday, 11 April 2015 at 09:41:07 UTC, Walter Bright wrote:A quick read of this suggests it is doing the Rust model of only one mutable reference at a time. Is this really viable with D?
Apr 12 2015
On Sunday, 12 April 2015 at 13:12:05 UTC, Martin Nowak wrote:As a side note, I find that unique ownership is strangely missing from our discussions, yet it's a perfect ownership model for resources such as a File. https://github.com/D-Programming-Language/phobos/pull/3171I'm aware of it, but didn't want to open another can of worms. I have a vague idea what to do about it, based on deadalnix' "isolated" idea and the already existing uniqueness concept. I need to make up my mind about moving though, whether the benefits of making the compiler know about it are worth the added complexity.
Apr 12 2015
On Saturday, 11 April 2015 at 09:28:46 UTC, Marc Schütz wrote:On Friday, 10 April 2015 at 23:12:55 UTC, deadalnix wrote:If we somehow know for a fact that the object really is a reference counted object, then the cost should be acceptable. Running the postblit will consist of incrementing a reference count and nothing else. There's no other way I can think of that permits passing the object safely. I think the one thing in the DIP I'm not sure of is the definition of what is a reference counted object. Say you write this. struct Widget { byte* data; size_t length; trusted opAssign(ref const(Widget) other) { length = other.length; data = malloc(length); memcpy(cast(void*) data, cast(void*) other.data, length); } trusted this(this) { auto oldData = data; data = malloc(length); memcpy(cast(void*) data, cast(void*) oldData, length); } trusted ~this() { free(data); } } Why would you want to do this? Who knows. According to DIP77 the object above is defined to be a reference counted object, when it isn't. If we're rejecting the C++ answer of "don't write code that way," then the same rejection should apply here. We need to be able to say with 100% certainty that we are dealing with a reference counted object, or at least an object where we know the postblit is so trivial the cost of calling it will be small.On Friday, 10 April 2015 at 10:02:01 UTC, Martin Nowak wrote:It's not acceptable that it happens behind the user's back. Costly operations must be explicit.On Wednesday, 8 April 2015 at 23:11:08 UTC, Walter Bright wrote:Only the first pass by ref create a copy. You can then pass the ref down all you want without copy. That is an acceptable cost IMO.http://wiki.dlang.org/DIP77So someone passes an RCO via ref to avoid the inc/dec, and because that imposes safety issues we turn it into some sort of pass by value under the hood, defeating the purpose, and provide an opt-out via system opAssign. Wouldn't it more straightforward to make pass-by-ref unsafe ( system) for RCOs? Then the only thing missing to make this equally powerful, would be an optimization opportunity for the compiler to elide copies of pass-by-value RCOs, e.g. it could avoid calling the postblit when the function retains the refcount.
Apr 11 2015
On Saturday, 11 April 2015 at 10:14:00 UTC, w0rp wrote:I think the one thing in the DIP I'm not sure of is the definition of what is a reference counted object.I believe it's still defined by DIP74? http://wiki.dlang.org/DIP74
Apr 11 2015
On Saturday, 11 April 2015 at 09:28:46 UTC, Marc Schütz wrote:It's not acceptable that it happens behind the user's back. Costly operations must be explicit.Nothing is costly here.
Apr 11 2015
On Saturday, 11 April 2015 at 20:40:20 UTC, deadalnix wrote:On Saturday, 11 April 2015 at 09:28:46 UTC, Marc Schütz wrote:Of course it is: http://forum.dlang.org/post/iehijjgdlfouplcngrjy forum.dlang.orgIt's not acceptable that it happens behind the user's back. Costly operations must be explicit.Nothing is costly here.
Apr 12 2015
On Wednesday, 8 April 2015 at 23:11:08 UTC, Walter Bright wrote:http://wiki.dlang.org/DIP77In general, this is way too much focused on reference counting. The DIP does define "RCO" in more general terms, but still, it feels like the wrong approach. You also seem to look at Rust's type system from the same POV ("only one mutable reference at a time, for efficiency"), but that's not the point at all: it's about safety in general, not efficiency for RC. It encompasses so much more: memory safety, race-free sharing of data, avoiding iterator invalidation... DIP77 cannot help with general iterator invalidation at all. Another thing that just feels wrong is the automagic copying. We're passing something by `ref`, and the compiler inserts a copy behind our back?! And this isn't even visible to the user... Because the topic is correctness, safe/ system seems the correct way to approach the problem. The compiler should just treat unsafe pass-by-ref as system, as Martin suggests. Basically, instead of inserting a copy, pass-by-ref will be system, when no copy would need to be inserted, it will be safe. I also think that the unsafety detection heuristic is too simplistic. When scope/return is extended to pointers and other kinds of references, there would probably be way too many false positives. A more sophisticated analysis is necessary that can more realistically determine when mutable aliasing can occur. E.g., it can also take uniqueness into account. Besides, the address and slice operators also need to be taken into account, and these can appear outside of function calls.
Apr 10 2015
On 4/10/2015 7:23 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net>" wrote:On Wednesday, 8 April 2015 at 23:11:08 UTC, Walter Bright wrote:D uses ranges, not iterators.http://wiki.dlang.org/DIP77In general, this is way too much focused on reference counting. The DIP does define "RCO" in more general terms, but still, it feels like the wrong approach. You also seem to look at Rust's type system from the same POV ("only one mutable reference at a time, for efficiency"), but that's not the point at all: it's about safety in general, not efficiency for RC. It encompasses so much more: memory safety, race-free sharing of data, avoiding iterator invalidation... DIP77 cannot help with general iterator invalidation at all.Another thing that just feels wrong is the automagic copying. We're passing something by `ref`, and the compiler inserts a copy behind our back?! And this isn't even visible to the user... Because the topic is correctness, safe/ system seems the correct way to approach the problem. The compiler should just treat unsafe pass-by-ref as system, as Martin suggests. Basically, instead of inserting a copy, pass-by-ref will be system, when no copy would need to be inserted, it will be safe.A difficulty with that is the semantics will change as the compiler improves and gets better at realizing no copy would be needed. Having the safety be "implementation defined" would be unhappy.I also think that the unsafety detection heuristic is too simplistic. When scope/return is extended to pointers and other kinds of references, there would probably be way too many false positives. A more sophisticated analysis is necessary that can more realistically determine when mutable aliasing can occur. E.g., it can also take uniqueness into account. Besides, the address and slice operators also need to be taken into account, and these can appear outside of function calls.I expect any use of RCO's necessarily means the implementation of the RCO is unsafe (after all, it calls free()), but a safe interface is provided. The safe interface to an RCO is tightly controlled with 'return ref'.
Apr 10 2015
On Friday, 10 April 2015 at 17:43:00 UTC, Walter Bright wrote:On 4/10/2015 7:23 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net>" wrote:I used "iterator invalidation" because it is an established term. You get the same problems with ranges, once the contents aren't GC managed. And even if they are, your code is merely memory safe, but not necessarily correct. stdin.byLine() without idup is a prime example.On Wednesday, 8 April 2015 at 23:11:08 UTC, Walter Bright wrote:D uses ranges, not iterators.http://wiki.dlang.org/DIP77In general, this is way too much focused on reference counting. The DIP does define "RCO" in more general terms, but still, it feels like the wrong approach. You also seem to look at Rust's type system from the same POV ("only one mutable reference at a time, for efficiency"), but that's not the point at all: it's about safety in general, not efficiency for RC. It encompasses so much more: memory safety, race-free sharing of data, avoiding iterator invalidation... DIP77 cannot help with general iterator invalidation at all.Agreed, it needs to be specified. I'm aware that this is difficult. Though, why can't we use the same approach we use in other cases? Be restrictive at first, later accept more, as we refine the specification... At some point we'll find the sweet spot between false negatives and complexity of specification, and can stabilize on it, so that other compilers have a non-moving target.Another thing that just feels wrong is the automagic copying. We're passing something by `ref`, and the compiler inserts a copy behind our back?! And this isn't even visible to the user... Because the topic is correctness, safe/ system seems the correct way to approach the problem. The compiler should just treat unsafe pass-by-ref as system, as Martin suggests. Basically, instead of inserting a copy, pass-by-ref will be system, when no copy would need to be inserted, it will be safe.A difficulty with that is the semantics will change as the compiler improves and gets better at realizing no copy would be needed. Having the safety be "implementation defined" would be unhappy.Uhm... how is this related to what I wrote? Example: void foo() safe { RCArray!int arr = [0,1,2]; { int* p = &arr[0]; // legal under new scope rules RCArray!int other; arr = other; writeln(*p); // OOPS } } This shows that with the extended scope rules (i.e. scope not restricted to `ref`), the borrowing can happen everywhere, not just on function calls. By your rules, every address and slice operator applied to a mutable local would need to trigger the copying, because the resulting (borrowed) reference exists in the same scope as the original variable (owner). I'd prefer instead to make writing to the owner unsafe, as long as borrowed references to it exist (this also includes potential writes, like passing a mutable ref to another function). This doesn't require copying behind the user's back, and allows the user to choose the solution best suited for the situation: manual copying, deferring the write to the owner, trusted...I also think that the unsafety detection heuristic is too simplistic. When scope/return is extended to pointers and other kinds of references, there would probably be way too many false positives. A more sophisticated analysis is necessary that can more realistically determine when mutable aliasing can occur. E.g., it can also take uniqueness into account. Besides, the address and slice operators also need to be taken into account, and these can appear outside of function calls.I expect any use of RCO's necessarily means the implementation of the RCO is unsafe (after all, it calls free()), but a safe interface is provided. The safe interface to an RCO is tightly controlled with 'return ref'.
Apr 10 2015
On 4/10/2015 11:28 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net>" wrote:Example: void foo() safe { RCArray!int arr = [0,1,2]; { int* p = &arr[0]; // legal under new scope rulesThis would be a bad design of an RCO. RCO's must be constructed to not allow pointers to the payload other than by ref.RCArray!int other; arr = other; writeln(*p); // OOPS } }
Apr 10 2015
On Friday, 10 April 2015 at 21:26:14 UTC, Walter Bright wrote:This would be a bad design of an RCO. RCO's must be constructed to not allow pointers to the payload other than by ref.And taking the address of that is already unsafe.
Apr 11 2015
On Saturday, 11 April 2015 at 09:15:19 UTC, Martin Nowak wrote:On Friday, 10 April 2015 at 21:26:14 UTC, Walter Bright wrote:It isn't under my proposal, which Walter has already accepted the most important part of.This would be a bad design of an RCO. RCO's must be constructed to not allow pointers to the payload other than by ref.And taking the address of that is already unsafe.
Apr 11 2015
On Friday, 10 April 2015 at 21:26:14 UTC, Walter Bright wrote:On 4/10/2015 11:28 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net>" wrote:There is no reason for this restriction. But if this is your opinion, why did you agree to "implement 'scope' and 'return' for arrays, classes, and pointers"? http://forum.dlang.org/post/mfhkbm$2vbk$1 digitalmars.com It makes no sense to implement that, but not allow it to be used safely.Example: void foo() safe { RCArray!int arr = [0,1,2]; { int* p = &arr[0]; // legal under new scope rulesThis would be a bad design of an RCO. RCO's must be constructed to not allow pointers to the payload other than by ref.
Apr 11 2015
On 4/11/2015 2:18 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net>" wrote:On Friday, 10 April 2015 at 21:26:14 UTC, Walter Bright wrote:The reason is to prevent unsafe access of the payload.On 4/10/2015 11:28 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net>" wrote:There is no reason for this restriction.Example: void foo() safe { RCArray!int arr = [0,1,2]; { int* p = &arr[0]; // legal under new scope rulesThis would be a bad design of an RCO. RCO's must be constructed to not allow pointers to the payload other than by ref.But if this is your opinion, why did you agree to "implement 'scope' and 'return' for arrays, classes, and pointers"? http://forum.dlang.org/post/mfhkbm$2vbk$1 digitalmars.com It makes no sense to implement that, but not allow it to be used safely.In your example posted upthread, it wasn't safe. Perhaps scoped pointers can't be made safe for RCOs, or perhaps the proposal needs more thinking. I don't know at the moment.
Apr 11 2015
On 04/09/2015 01:10 AM, Walter Bright wrote:http://wiki.dlang.org/DIP77In the first problem example: struct S { RCArray!T array; } void main() { auto s = S(RCArray!T([T()])); // s.array's refcount is now 1 foo(s, s.array[0]); // pass by ref } void foo(ref S s, ref T t) { s.array = RCArray!T([]); // drop the old s.array t.doSomething(); // oops, t is gone } What do you do to pin s.array? auto tmp = s; or auto tmp = s.array;
Apr 10 2015
On 4/10/2015 2:11 PM, Martin Nowak wrote:On 04/09/2015 01:10 AM, Walter Bright wrote:The latter.http://wiki.dlang.org/DIP77In the first problem example: struct S { RCArray!T array; } void main() { auto s = S(RCArray!T([T()])); // s.array's refcount is now 1 foo(s, s.array[0]); // pass by ref } void foo(ref S s, ref T t) { s.array = RCArray!T([]); // drop the old s.array t.doSomething(); // oops, t is gone } What do you do to pin s.array? auto tmp = s; or auto tmp = s.array;
Apr 10 2015
On 2015-04-10 21:29:19 +0000, Walter Bright <newshound2 digitalmars.com> said:On 4/10/2015 2:11 PM, Martin Nowak wrote:And how is it pinned in this case? struct S { private RCArray!T array; ref T opIndex(int index) return { return array[index]; } void clear() { s.array = RCArray!T([]); } } void main() { auto s = S(RCArray!T([T()])); // s.array's refcount is now 1 foo(s, s[0]); // pass by ref } void foo(ref S s, ref T t) { s.clear(); // drop the old s.array t.doSomething(); // oops, t is gone } -- Michel Fortin michel.fortin michelf.ca http://michelf.caOn 04/09/2015 01:10 AM, Walter Bright wrote:The latter.http://wiki.dlang.org/DIP77In the first problem example: struct S { RCArray!T array; } void main() { auto s = S(RCArray!T([T()])); // s.array's refcount is now 1 foo(s, s.array[0]); // pass by ref } void foo(ref S s, ref T t) { s.array = RCArray!T([]); // drop the old s.array t.doSomething(); // oops, t is gone } What do you do to pin s.array? auto tmp = s; or auto tmp = s.array;
Apr 10 2015
On Friday, 10 April 2015 at 21:50:13 UTC, Michel Fortin wrote:On 2015-04-10 21:29:19 +0000, Walter Bright <newshound2 digitalmars.com> said:AFAICT it would create a temporary copy of s.array, which would keep t valid.On 4/10/2015 2:11 PM, Martin Nowak wrote:And how is it pinned in this case? struct S { private RCArray!T array; ref T opIndex(int index) return { return array[index]; } void clear() { s.array = RCArray!T([]); } } void main() { auto s = S(RCArray!T([T()])); // s.array's refcount is now 1 foo(s, s[0]); // pass by ref } void foo(ref S s, ref T t) { s.clear(); // drop the old s.array t.doSomething(); // oops, t is gone }On 04/09/2015 01:10 AM, Walter Bright wrote:The latter.http://wiki.dlang.org/DIP77In the first problem example: struct S { RCArray!T array; } void main() { auto s = S(RCArray!T([T()])); // s.array's refcount is now 1 foo(s, s.array[0]); // pass by ref } void foo(ref S s, ref T t) { s.array = RCArray!T([]); // drop the old s.array t.doSomething(); // oops, t is gone } What do you do to pin s.array? auto tmp = s; or auto tmp = s.array;Nope. It'll scan at compile time the types reachable through the parameters. If any of those types are RCO's that have a type that matches a ref parameter, theref parameter's RCO will get copied.
Apr 10 2015
On 4/10/2015 2:50 PM, Michel Fortin wrote:And how is it pinned in this case? struct S { private RCArray!T array; ref T opIndex(int index) return { return array[index]; } void clear() { s.array = RCArray!T([]); } } void main() { auto s = S(RCArray!T([T()])); // s.array's refcount is now 1 foo(s, s[0]); // pass by refThe s[0] is preceded by tmp=s; Because T is reachable from typeof(first argument s)} void foo(ref S s, ref T t) { s.clear(); // drop the old s.array t.doSomething(); // oops, t is gone }
Apr 10 2015
On 04/10/2015 11:29 PM, Walter Bright wrote:The latter.Can you update that part in the DIP, it wasn't clear that the temporary selectively pins RCO fields of a normal struct passed by ref.
Apr 10 2015
On Friday, 10 April 2015 at 23:18:59 UTC, Martin Nowak wrote:On 04/10/2015 11:29 PM, Walter Bright wrote:If a struct has RCO fields, shouldn't it be an RCO itself, and as such be pinned ? It sounds like this is implied in the DIP.The latter.Can you update that part in the DIP, it wasn't clear that the temporary selectively pins RCO fields of a normal struct passed by ref.
Apr 10 2015
On 2015-04-10 23:22:17 +0000, "deadalnix" <deadalnix gmail.com> said:On Friday, 10 April 2015 at 23:18:59 UTC, Martin Nowak wrote:Not necessarily. A disabled postblit could make it no longer RCO (including a disabled postblit in one of the fields).On 04/10/2015 11:29 PM, Walter Bright wrote:If a struct has RCO fields, shouldn't it be an RCO itself, and as such be pinned ?The latter.Can you update that part in the DIP, it wasn't clear that the temporary selectively pins RCO fields of a normal struct passed by ref.It sounds like this is implied in the DIP.That's what I thought too. But when confronted to a case where that wouldn't work Walter said in this thread that the compiler would make a temporary of the fields. So I'm not too sure what to think anymore. The DIP should clarify what happens with disabled postblit and RCO fields inside non-RCO structs. -- Michel Fortin michel.fortin michelf.ca http://michelf.ca
Apr 10 2015
On 4/10/2015 4:18 PM, Martin Nowak wrote:On 04/10/2015 11:29 PM, Walter Bright wrote:It pins RCO objects, however they are derived.The latter.Can you update that part in the DIP, it wasn't clear that the temporary selectively pins RCO fields of a normal struct passed by ref.
Apr 10 2015
On 04/09/2015 01:10 AM, Walter Bright wrote:http://wiki.dlang.org/DIP77It's a very interesting proposal to tackle this specific problem. As with all the scope/lifetime related stuff, I find it extremely difficult to anticipate all the needs and foresee how this will integrate with the rest of the language, or even the other scope related DIPs. At this point it might be better to make a dmd branch and throw up a prototype for all the scope/ref-counted work. The litmus test for a successful design would be safe, efficient, nogc containers.
Apr 11 2015