digitalmars.D - Local functions infer attributes?
- Manu via Digitalmars-d (12/12) Sep 27 2014 void f() pure nothrow @nogc
- deadalnix (6/19) Sep 27 2014 No as the function could be returned and used elsewhere, where
- Walter Bright (3/23) Sep 27 2014 Since the function body is always present, inference should always be do...
- deadalnix (3/6) Sep 27 2014 If you have a control flow graph to analyze it can become quite
- Walter Bright (2/6) Sep 27 2014 Nope! It happens as part of semantic analysis.
- deadalnix (3/13) Sep 27 2014 Obviously, it does. The complexity of the computation still can
- Walter Bright (2/12) Sep 27 2014 If you look at how it is currently implemented, you'll see it doesn't go...
- bearophile (5/7) Sep 28 2014 Filed:
- Walter Bright (2/4) Sep 28 2014 Thanks!
- Trass3r (5/7) Sep 30 2014 Doesn't the compiler have to do that anyway?
- deadalnix (3/11) Sep 30 2014 It is for the function body, but most qualifier are transitive,
- Andrei Alexandrescu (11/23) Sep 28 2014 Interesting. I'd guess probably not, e.g. a function may define a static...
- Manu via Digitalmars-d (14/40) Sep 28 2014 I was out of town (was on my phone), and now I'm home with 2 guests,
- Walter Bright (2/10) Sep 28 2014 S!(int, S*)
- Manu via Digitalmars-d (21/33) Sep 28 2014 That's different.
- Walter Bright (4/24) Sep 28 2014 You're right that tuples in D cannot contain storage classes (and ref is...
- Timon Gehr (5/6) Sep 28 2014 void foo(ref int x){}
- Walter Bright (2/9) Sep 28 2014 You're right, I had forgotten about that.
- Daniel N (9/16) Sep 29 2014 Well, only if you are sufficiently desperate. ;)
- Manu via Digitalmars-d (5/26) Sep 30 2014 I have actually thought of that ;) ... but I tend to think that only D
- deadalnix (4/9) Sep 30 2014 You can probably wrap this in a nice library solution with an
- Daniel N (14/23) Sep 30 2014 Hmm, I see your point... otherwise maybe user facing code survive
- John Colvin (6/38) Sep 30 2014 Perhaps this might help you a little:
- John Colvin (3/43) Sep 30 2014 Also, I just wrote it in a few hours after seeing your post, so
- Manu via Digitalmars-d (16/45) Sep 29 2014 I know, that's my whole point. I think 'storage class' is the original s...
- Daniel N (7/21) Oct 10 2014 Yet another solution...
- Andrei Alexandrescu (35/47) Sep 29 2014 Thanks, don't feel under any obligation express or implied to follow
- deadalnix (14/17) Sep 29 2014 I think this is because ref have several conflated meaning:
- Manu via Digitalmars-d (29/49) Sep 29 2014 I don't see ref that way at all. I see it so much simpler than that:
- deadalnix (5/13) Sep 29 2014 "I don't agree with your diagnostic. I'm suing ref conforming of
- Manu via Digitalmars-d (11/22) Sep 29 2014 ... huh?
- Manu via Digitalmars-d (93/140) Sep 29 2014 Well, after your unflattering caricature, I intend to take the time to
- bearophile (9/12) Sep 29 2014 If your think your choice was the wrong one, don't invest even
- Manu via Digitalmars-d (33/43) Sep 29 2014 It's not to say it's the 'wrong choice'. I'm definitely an early
- bearophile (23/31) Sep 29 2014 Most of the times I have no problems with D ref. Perhaps you are
- ixid (18/51) Sep 30 2014 You're a vital alternative voice, please try to stick with us.
- Sad panda (5/52) Sep 30 2014 +10 <3
- Andrei Alexandrescu (2/4) Sep 30 2014 Indeed that's an accurate characterization of my POV. -- Andrei
- bearophile (5/8) Sep 30 2014 Manu is quite more expert than me in the kind of code he writes.
- bachmeier (4/8) Sep 30 2014 There are only two kinds of languages: the ones people complain
- Walter Bright (5/8) Sep 30 2014 Or heck, ask the n.g. Lots of people here are very creative in their
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (5/11) Sep 30 2014 Try to add some rudimentary support for ref in the compiler
- Wyatt (7/8) Sep 30 2014 Semi-tangential to this discussion, but this bit hits on
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (14/18) Sep 30 2014 That's a very perceptive observation. :)
void f() pure nothrow nogc { void localFunc() { } localFunc(); } Complains because localFunc is not nogc or nothrow. Doesn't complain about pure though. Is it reasonable to say that the scope of the outer function is nothrow+ nogc, and therefore everything declared within should also be so?
Sep 27 2014
On Sunday, 28 September 2014 at 02:42:29 UTC, Manu via Digitalmars-d wrote:void f() pure nothrow nogc { void localFunc() { } localFunc(); } Complains because localFunc is not nogc or nothrow. Doesn't complain about pure though. Is it reasonable to say that the scope of the outer function is nothrow+ nogc, and therefore everything declared within should also be so?No as the function could be returned and used elsewhere, where these attribute aren't necessary. Also, inferring everything is quite expensive and we want D to compile fast. But maybe inference could be triggered on error ?
Sep 27 2014
On 9/27/2014 7:56 PM, deadalnix wrote:On Sunday, 28 September 2014 at 02:42:29 UTC, Manu via Digitalmars-d wrote:Since the function body is always present, inference should always be done. It isn't costly. Should file an enhancement request on this.void f() pure nothrow nogc { void localFunc() { } localFunc(); } Complains because localFunc is not nogc or nothrow. Doesn't complain about pure though. Is it reasonable to say that the scope of the outer function is nothrow+ nogc, and therefore everything declared within should also be so?No as the function could be returned and used elsewhere, where these attribute aren't necessary. Also, inferring everything is quite expensive and we want D to compile fast. But maybe inference could be triggered on error ?
Sep 27 2014
On Sunday, 28 September 2014 at 03:08:09 UTC, Walter Bright wrote:Since the function body is always present, inference should always be done. It isn't costly. Should file an enhancement request on this.If you have a control flow graph to analyze it can become quite costly.
Sep 27 2014
On 9/27/2014 8:50 PM, deadalnix wrote:On Sunday, 28 September 2014 at 03:08:09 UTC, Walter Bright wrote:Nope! It happens as part of semantic analysis.Since the function body is always present, inference should always be done. It isn't costly. Should file an enhancement request on this.If you have a control flow graph to analyze it can become quite costly.
Sep 27 2014
On Sunday, 28 September 2014 at 04:04:24 UTC, Walter Bright wrote:On 9/27/2014 8:50 PM, deadalnix wrote:Obviously, it does. The complexity of the computation still can go quite high.On Sunday, 28 September 2014 at 03:08:09 UTC, Walter Bright wrote:Nope! It happens as part of semantic analysis.Since the function body is always present, inference should always be done. It isn't costly. Should file an enhancement request on this.If you have a control flow graph to analyze it can become quite costly.
Sep 27 2014
On 9/27/2014 10:48 PM, deadalnix wrote:On Sunday, 28 September 2014 at 04:04:24 UTC, Walter Bright wrote:If you look at how it is currently implemented, you'll see it doesn't go high.On 9/27/2014 8:50 PM, deadalnix wrote:Obviously, it does. The complexity of the computation still can go quite high.On Sunday, 28 September 2014 at 03:08:09 UTC, Walter Bright wrote:Nope! It happens as part of semantic analysis.Since the function body is always present, inference should always be done. It isn't costly. Should file an enhancement request on this.If you have a control flow graph to analyze it can become quite costly.
Sep 27 2014
deadalnix:the function could be returned and used elsewhere, where these attribute aren't necessary.Filed: https://issues.dlang.org/show_bug.cgi?id=13550 Bye, bearophile
Sep 28 2014
On 9/28/2014 1:49 AM, bearophile wrote:Filed: https://issues.dlang.org/show_bug.cgi?id=13550Thanks!
Sep 28 2014
On Sunday, 28 September 2014 at 02:56:57 UTC, deadalnix wrote:Also, inferring everything is quite expensive and we want D to compile fast.Doesn't the compiler have to do that anyway? I'd expect a proper compiler to check if my code is actually what I claim it is. It's quite easy to mark something as e.g. nogc in the first version and later on add code with allocations.
Sep 30 2014
On Tuesday, 30 September 2014 at 08:33:27 UTC, Trass3r wrote:On Sunday, 28 September 2014 at 02:56:57 UTC, deadalnix wrote:It is for the function body, but most qualifier are transitive, so depends on the inference on other function.Also, inferring everything is quite expensive and we want D to compile fast.Doesn't the compiler have to do that anyway? I'd expect a proper compiler to check if my code is actually what I claim it is. It's quite easy to mark something as e.g. nogc in the first version and later on add code with allocations.
Sep 30 2014
On 9/27/14, 7:42 PM, Manu via Digitalmars-d wrote:void f() pure nothrow nogc { void localFunc() { } localFunc(); } Complains because localFunc is not nogc or nothrow. Doesn't complain about pure though. Is it reasonable to say that the scope of the outer function is nothrow+ nogc, and therefore everything declared within should also be so?Interesting. I'd guess probably not, e.g. a function may define a static local function and return its address (without either throwing or creating garbage), whereas that local function itself may do whatever it pleases. However, local functions have their body available by definition so they should have all deducible attributes deducted. That should take care of the problem. Andrei P.S. I also notice that my latest attempt at establishing communication has remained ignored.
Sep 28 2014
On 28 September 2014 22:21, Andrei Alexandrescu via Digitalmars-d <digitalmars-d puremagic.com> wrote:On 9/27/14, 7:42 PM, Manu via Digitalmars-d wrote:I was out of town (was on my phone), and now I'm home with 2 guests, and we're working together. I can't sit and craft a pile of example cases until I'm alone and have time to do so. I haven't ignored it, but I need to find the time to give you what you want. That said, my friend encountered one of my frequently recurring pain cases himself yesterday: struct S(T...) { void f(T args) {} } S!(int, ref S) fail; // <-- no clean way to do this. I need this very frequently, and he reached for it too, so I can't be that weird.void f() pure nothrow nogc { void localFunc() { } localFunc(); } Complains because localFunc is not nogc or nothrow. Doesn't complain about pure though. Is it reasonable to say that the scope of the outer function is nothrow+ nogc, and therefore everything declared within should also be so?Interesting. I'd guess probably not, e.g. a function may define a static local function and return its address (without either throwing or creating garbage), whereas that local function itself may do whatever it pleases. However, local functions have their body available by definition so they should have all deducible attributes deducted. That should take care of the problem. Andrei P.S. I also notice that my latest attempt at establishing communication has remained ignored.
Sep 28 2014
On 9/28/2014 5:38 PM, Manu via Digitalmars-d wrote:That said, my friend encountered one of my frequently recurring pain cases himself yesterday: struct S(T...) { void f(T args) {} } S!(int, ref S) fail; // <-- no clean way to do this. I need this very frequently, and he reached for it too, so I can't be that weird.S!(int, S*)
Sep 28 2014
On 29 September 2014 10:51, Walter Bright via Digitalmars-d <digitalmars-d puremagic.com> wrote:On 9/28/2014 5:38 PM, Manu via Digitalmars-d wrote:That's different. I feel like I have to somehow justify to you guys how meta code works in D. I have meta code that is no less than 5 layers deep. It's complex, but at the same time, somehow surprisingly elegant and simple (this is the nature of D I guess). If I now assume throughout my meta "pointer means ref", then when I actually pass a pointer in, the meta can't know if it was meant to be a ref or not. It results in complex explicit logic to handle at almost every point due to a loss of information. You can't call f() with the same syntax anymore (you need an '&') which is a static if in the meta, you can't use the S* arg in the same meta (needs a '*') which is another static if. Assignments are changed, and unexpected indexing mechanics appear. When implementation logic expects and understands the distinction between pointers and ref's, this confuses that logic. When I interface between languages (everything I never do binds to at least C++, and in this case, also Lua), this complicates the situation. I can't conflate 2 things that aren't the same. It leads to a lot of mess in a lot of places.That said, my friend encountered one of my frequently recurring pain cases himself yesterday: struct S(T...) { void f(T args) {} } S!(int, ref S) fail; // <-- no clean way to do this. I need this very frequently, and he reached for it too, so I can't be that weird.S!(int, S*)
Sep 28 2014
On 9/28/2014 6:31 PM, Manu via Digitalmars-d wrote:You're right that tuples in D cannot contain storage classes (and ref is just one storage class, there's also out and in, etc.). You can use autoref, but I haven't understood why that doesn't work for you.S!(int, S*)That's different. I feel like I have to somehow justify to you guys how meta code works in D. I have meta code that is no less than 5 layers deep. It's complex, but at the same time, somehow surprisingly elegant and simple (this is the nature of D I guess). If I now assume throughout my meta "pointer means ref", then when I actually pass a pointer in, the meta can't know if it was meant to be a ref or not. It results in complex explicit logic to handle at almost every point due to a loss of information. You can't call f() with the same syntax anymore (you need an '&') which is a static if in the meta, you can't use the S* arg in the same meta (needs a '*') which is another static if. Assignments are changed, and unexpected indexing mechanics appear. When implementation logic expects and understands the distinction between pointers and ref's, this confuses that logic. When I interface between languages (everything I never do binds to at least C++, and in this case, also Lua), this complicates the situation. I can't conflate 2 things that aren't the same. It leads to a lot of mess in a lot of places.
Sep 28 2014
On 09/29/2014 04:43 AM, Walter Bright wrote:You're right that tuples in D cannot contain storage classesvoid foo(ref int x){} alias p=ParameterTypeTuple!foo; pragma(msg, p); // (ref int) (But this does not help.)
Sep 28 2014
On 9/28/2014 9:23 PM, Timon Gehr wrote:On 09/29/2014 04:43 AM, Walter Bright wrote:You're right, I had forgotten about that.You're right that tuples in D cannot contain storage classesvoid foo(ref int x){} alias p=ParameterTypeTuple!foo; pragma(msg, p); // (ref int) (But this does not help.)
Sep 28 2014
On Monday, 29 September 2014 at 04:23:08 UTC, Timon Gehr wrote:On 09/29/2014 04:43 AM, Walter Bright wrote:Well, only if you are sufficiently desperate. ;) struct S(alias T) { void f(ParameterTypeTuple!T p) { } } S!((ref int x, int y){}) s;You're right that tuples in D cannot contain storage classesvoid foo(ref int x){} alias p=ParameterTypeTuple!foo; pragma(msg, p); // (ref int) (But this does not help.)
Sep 29 2014
On 30 September 2014 16:06, Daniel N via Digitalmars-d <digitalmars-d puremagic.com> wrote:On Monday, 29 September 2014 at 04:23:08 UTC, Timon Gehr wrote:I have actually thought of that ;) ... but I tend to think that only D users present on this forum are likely to make sense of that code, and why.On 09/29/2014 04:43 AM, Walter Bright wrote:Well, only if you are sufficiently desperate. ;) struct S(alias T) { void f(ParameterTypeTuple!T p) { } } S!((ref int x, int y){}) s;You're right that tuples in D cannot contain storage classesvoid foo(ref int x){} alias p=ParameterTypeTuple!foo; pragma(msg, p); // (ref int) (But this does not help.)
Sep 30 2014
On Tuesday, 30 September 2014 at 07:10:08 UTC, Manu via Digitalmars-d wrote:I have actually thought of that ;) ... but I tend to think that only D users present on this forum are likely to make sense of that code, and why.You can probably wrap this in a nice library solution with an explicit name.
Sep 30 2014
On Tuesday, 30 September 2014 at 07:18:20 UTC, deadalnix wrote:On Tuesday, 30 September 2014 at 07:10:08 UTC, Manu via Digitalmars-d wrote:Hmm, I see your point... otherwise maybe user facing code survive using a string? struct S_impl(alias T) { void f(ParameterTypeTuple!T p) { } } template S(string decl) { mixin("alias S = S_impl!((" ~ decl ~ ") {});"); } S!"ref int x, int y" s;I have actually thought of that ;) ... but I tend to think that only D users present on this forum are likely to make sense of that code, and why.You can probably wrap this in a nice library solution with an explicit name.
Sep 30 2014
On Tuesday, 30 September 2014 at 07:10:08 UTC, Manu via Digitalmars-d wrote:On 30 September 2014 16:06, Daniel N via Digitalmars-d <digitalmars-d puremagic.com> wrote:Perhaps this might help you a little: http://code.dlang.org/packages/storageclassutils sure, it's not as elegant as one would like, but it at least provides some basic utility.On Monday, 29 September 2014 at 04:23:08 UTC, Timon Gehr wrote:I have actually thought of that ;) ... but I tend to think that only D users present on this forum are likely to make sense of that code, and why.On 09/29/2014 04:43 AM, Walter Bright wrote:Well, only if you are sufficiently desperate. ;) struct S(alias T) { void f(ParameterTypeTuple!T p) { } } S!((ref int x, int y){}) s;You're right that tuples in D cannot contain storage classesvoid foo(ref int x){} alias p=ParameterTypeTuple!foo; pragma(msg, p); // (ref int) (But this does not help.)
Sep 30 2014
On Tuesday, 30 September 2014 at 13:47:22 UTC, John Colvin wrote:On Tuesday, 30 September 2014 at 07:10:08 UTC, Manu via Digitalmars-d wrote:Also, I just wrote it in a few hours after seeing your post, so obviously there are plenty of improvements that could be made.On 30 September 2014 16:06, Daniel N via Digitalmars-d <digitalmars-d puremagic.com> wrote:Perhaps this might help you a little: http://code.dlang.org/packages/storageclassutils sure, it's not as elegant as one would like, but it at least provides some basic utility.On Monday, 29 September 2014 at 04:23:08 UTC, Timon Gehr wrote:I have actually thought of that ;) ... but I tend to think that only D users present on this forum are likely to make sense of that code, and why.On 09/29/2014 04:43 AM, Walter Bright wrote:Well, only if you are sufficiently desperate. ;) struct S(alias T) { void f(ParameterTypeTuple!T p) { } } S!((ref int x, int y){}) s;You're right that tuples in D cannot contain storage classesvoid foo(ref int x){} alias p=ParameterTypeTuple!foo; pragma(msg, p); // (ref int) (But this does not help.)
Sep 30 2014
On 29 September 2014 12:43, Walter Bright via Digitalmars-d <digitalmars-d puremagic.com> wrote:On 9/28/2014 6:31 PM, Manu via Digitalmars-d wrote:I know, that's my whole point. I think 'storage class' is the original sin. in is declared as scope const, or in my fantasy world scope(const(T)). out is the only interesting storage class (conceptually) I've used. It is effectively just an alias for ref, but it also encodes some special non-type information, which is to initialise prior to the call.You're right that tuples in D cannot contain storage classes (and ref is just one storage class, there's also out and in, etc.).S!(int, S*)That's different. I feel like I have to somehow justify to you guys how meta code works in D. I have meta code that is no less than 5 layers deep. It's complex, but at the same time, somehow surprisingly elegant and simple (this is the nature of D I guess). If I now assume throughout my meta "pointer means ref", then when I actually pass a pointer in, the meta can't know if it was meant to be a ref or not. It results in complex explicit logic to handle at almost every point due to a loss of information. You can't call f() with the same syntax anymore (you need an '&') which is a static if in the meta, you can't use the S* arg in the same meta (needs a '*') which is another static if. Assignments are changed, and unexpected indexing mechanics appear. When implementation logic expects and understands the distinction between pointers and ref's, this confuses that logic. When I interface between languages (everything I never do binds to at least C++, and in this case, also Lua), this complicates the situation. I can't conflate 2 things that aren't the same. It leads to a lot of mess in a lot of places.You can use autoref, but I haven't understood why that doesn't work for you.I'm not writing java or python code here. I consider it a fundamental quality of a 'systems language', or perhaps just a native language, that I have the explicit power to produce binary I intend. I can't have the compiler deciding if something is to be ref or not. My code is rarely only consumed by other D code. I have lots of cross language linkage, and also dynamic libraries (which expect a specific ABI). auto ref wouldn't work in that situation I gave above anyway... S!(auto ref T) is no more valid than S!(ref T).
Sep 29 2014
On Monday, 29 September 2014 at 00:51:26 UTC, Walter Bright wrote:On 9/28/2014 5:38 PM, Manu via Digitalmars-d wrote:Yet another solution... http://dpaste.dzfl.pl/e28c55416ce2 ... locally you always use ref, but when instantiating another template you need to forward the original pointer type to the next level... this way it's possible to avoid an explosion of "static if":s.That said, my friend encountered one of my frequently recurring pain cases himself yesterday: struct S(T...) { void f(T args) {} } S!(int, ref S) fail; // <-- no clean way to do this. I need this very frequently, and he reached for it too, so I can't be that weird.S!(int, S*)
Oct 10 2014
On 9/28/14, 5:38 PM, Manu via Digitalmars-d wrote:I was out of town (was on my phone), and now I'm home with 2 guests, and we're working together. I can't sit and craft a pile of example cases until I'm alone and have time to do so. I haven't ignored it, but I need to find the time to give you what you want.Thanks, don't feel under any obligation express or implied to follow through.That said, my friend encountered one of my frequently recurring pain cases himself yesterday: struct S(T...) { void f(T args) {} } S!(int, ref S) fail; // <-- no clean way to do this. I need this very frequently, and he reached for it too, so I can't be that weird.I understand. The short answer to this is D cannot do that and we cannot afford to change the language to make it do that. There are two longer answers. The first longer answer is there are ways to do that if it's a necessity, as you know and probably did. I agree it's not clean/easy. The second longer answer is if you do this it means you're trying to write C++ in D: in C++ ref is part of the type (well... sort of) and therefore someone coming from C++ and translating the respective designs into D will find the change frustrating. I've seen this pattern several times. Most recent was in conjunction with iterators vs. ranges. There's discussion going on in C++ circles about adding ranges to C++. One common issue raised by people gravitates around designs where the choice of using iterators is long foregone, and would think that replacing iterators with ranges throughout should just work. Take a look: http://article.gmane.org/gmane.comp.lib.boost.devel/191978 The reality is algorithms implemented with ranges look different from algorithms implemented with iterators. Similarly, generic code with D will look different from generic code with C++. Our hope is, of course, that all told range-based and D-generics code has advantages going for it, but the most dramatic of those advantages most certainly won't be discovered and reaped in designs that are copies of the respective C++ ones. So you can't be that weird and neither is your friend, but I speculate that both of you have a solid C++ background :o). About this situation in particular, yes, ref being part of the type does help this declaration, but overall as a design decision for the C++ programming value its value is questionable. T& is not a first class type and that hurts everyone everywhere - you can't create a value of that types, and virtually all parts of the language have special rules telling what happens when the actual type is a reference type. I think Walter made the right call here and we shouldn't change anything. Andrei
Sep 29 2014
On Monday, 29 September 2014 at 08:02:45 UTC, Andrei Alexandrescu wrote:I understand. The short answer to this is D cannot do that and we cannot afford to change the language to make it do that. There are two longer answers.I think this is because ref have several conflated meaning: - "I want to mess up with the argument" (à la swap). This is the meaning it has right now. - "Burrowing". Which is the same as previous behavior, except for classes and delegates, so the whole scope story, as they are natural "reference types". - "Do not copy" aka const ref. This one is for performance reason. It doesn't really matter if a copy is made or not as the damn thing is const, but one want to avoid expensive copy when the thing passed down is fat. Each of them have their own set of cases where you want and do not want ref.
Sep 29 2014
On 30 September 2014 09:25, deadalnix via Digitalmars-d <digitalmars-d puremagic.com> wrote:On Monday, 29 September 2014 at 08:02:45 UTC, Andrei Alexandrescu wrote:I don't see ref that way at all. I see it so much simpler than that: ref is a type of pointer. It's effectively T(immutable(*)). It's uses are emergent from what it is; a good way to pass big things around in argument lists, or share references to a single instance of something. It also offers an advantage due to the nature that the pointer is immutable; you don't need the pointer syntax baggage (*, &) when dealing with ref's, which is very convenient in user code. I think all this 'meaning' is a mistake; all that does is confuse the matter. You don't attribute such 'meaning' to a normal pointer, it's a primitive type. If it's defined by some conceptual rubbish, then when it's attempted to be used in some situation that doesn't perfectly fit the conceptual attribution, you find yourself in awkward logical situations with weird edge cases. If you just say "it's an immutable pointer, and follows value syntax semantics for practical reasons", then it's very clear what it does. It's also very clear what that means to the ABI, and relationships with other languages. A similar mistake from C is where 'int' doesn't mean '32bits', it means some conceptual nonsense that seemed like a good idea at the time, but the result is, you don't really know what 'int' is, and everyone reinvents it so it works reliably (typedef int32 something).I understand. The short answer to this is D cannot do that and we cannot afford to change the language to make it do that. There are two longer answers.I think this is because ref have several conflated meaning: - "I want to mess up with the argument" (à la swap). This is the meaning it has right now. - "Burrowing". Which is the same as previous behavior, except for classes and delegates, so the whole scope story, as they are natural "reference types". - "Do not copy" aka const ref. This one is for performance reason. It doesn't really matter if a copy is made or not as the damn thing is const, but one want to avoid expensive copy when the thing passed down is fat.Each of them have their own set of cases where you want and do not want ref.I agree, cases where ref should be used are non-trivial. It may be a result of external factors, some user logic, or explicit request from user code. The fact that it lives outside the type system makes that whole reality very awkward indeed.
Sep 29 2014
On Tuesday, 30 September 2014 at 00:33:08 UTC, Manu via Digitalmars-d wrote:I don't see ref that way at all. I see it so much simpler than that: ref is a type of pointer. It's effectively T(immutable(*)). It's uses are emergent from what it is; a good way to pass big things around in argument lists, or share references to a single instance of something."I don't agree with your diagnostic. I'm suing ref conforming of cases 2 and 3 of your diagnostic". That sounds like a self defeating statement.
Sep 29 2014
On 30 September 2014 10:44, deadalnix via Digitalmars-d <digitalmars-d puremagic.com> wrote:On Tuesday, 30 September 2014 at 00:33:08 UTC, Manu via Digitalmars-d wrote:... huh? I'm not saying your analysis of use cases are false, I'm just saying that I felt the reasoning is backwards, and possibly conceptually limiting. I think the use cases should be emergent of the definition, not that the definition should be defined by (read: limited to) the typical uses. You said ref conflated several meanings, I'm just framing it differently. I don't think it conflates them, I think they're all good uses of the tool.I don't see ref that way at all. I see it so much simpler than that: ref is a type of pointer. It's effectively T(immutable(*)). It's uses are emergent from what it is; a good way to pass big things around in argument lists, or share references to a single instance of something."I don't agree with your diagnostic. I'm suing ref conforming of cases 2 and 3 of your diagnostic". That sounds like a self defeating statement.
Sep 29 2014
On 29 September 2014 18:02, Andrei Alexandrescu via Digitalmars-d <digitalmars-d puremagic.com> wrote:On 9/28/14, 5:38 PM, Manu via Digitalmars-d wrote:Well, after your unflattering caricature, I intend to take the time to try and craft some good examples of various cases. I also have a strong suspicion (valid or otherwise) that there is literally nothing I could do to convince you, no matter the quality of my evidence. There will always be the "it's too late", "it's a breaking change!", defence. Unless you and Walter are both invested in a change, I'm pretty certain it's impossible. So, your observation may well have been fair. Perhaps that is a true pattern of mine, but I don't think 'I'm just a dick like that', I think there is reason behind it. There is certainly time in the past where I've gone to great lengths to try and prove my cases. In more recent times, and as my (few) outstanding daily problems with the language have become more controversial, I've become fairly convinced that such effort on my part is just wasting my time, and only serves as a process for me to highlight my frustrations to myself. You obviously don't approach programming the same way I do, I can't appeal to you. Upon closer examination of my mood and feelings interacting with this forum recently, I realise that this is a significant factor in my interaction, although perhaps being mostly subconscious. Ie, I'm more likely to disappear and try and get some work done, than spend the time trying to win a futile argument. I did try very hard to extract myself from this NG, but it seems it's very hard to resist! When topics I care about appear, or when I'm just wildly frustrated about something that agitates me on a daily basis, I keep coming back! >_< Point is, I feel like I've been an engaged member of this community for a long time now, but I feel like I have practically nothing more to add. My experience and industry use cases are no longer interesting, they've presented any value that they had already. I get the feeling I've affected all of the change that I am capable of, and I need to decide if I'm happy with D as is, or not, rather than maintain my ambient frustration that it's sitting at 99%, with the last 1% unattainable to me unless I fork the language for my own use :/ Trouble for me is, I've invested so much time now. I find myself in a very awkward situation where I'm too far in... I can't go back to C++, but the situation is such that I'll never convince the rest of my colleagues to jump on board. Believe it or not, I'm a lot more reasonable (and patient) than most. I'm quite certain that these days, that thing that Scott Myers mentioned about the C++ committee; where practically anything can be used to justify anything, so getting changes approved is mostly an appeal to the emotional state of the people in charge, is already present in D.I was out of town (was on my phone), and now I'm home with 2 guests, and we're working together. I can't sit and craft a pile of example cases until I'm alone and have time to do so. I haven't ignored it, but I need to find the time to give you what you want.Thanks, don't feel under any obligation express or implied to follow through.What about someone *interacting* with C++, not just 'coming from'? uses ref a lot. In 6 years, the only time I've found an opportunity to use D in isolation, is a small webserver in vibe.d. My opinion is that ref is agreed to be critically important, as demonstrated to me by all the other languages I use.That said, my friend encountered one of my frequently recurring pain cases himself yesterday: struct S(T...) { void f(T args) {} } S!(int, ref S) fail; // <-- no clean way to do this. I need this very frequently, and he reached for it too, so I can't be that weird.I understand. The short answer to this is D cannot do that and we cannot afford to change the language to make it do that. There are two longer answers. The first longer answer is there are ways to do that if it's a necessity, as you know and probably did. I agree it's not clean/easy. The second longer answer is if you do this it means you're trying to write C++ in D: in C++ ref is part of the type (well... sort of) and therefore someone coming from C++ and translating the respective designs into D will find the change frustrating.I've seen this pattern several times. Most recent was in conjunction with iterators vs. ranges. There's discussion going on in C++ circles about adding ranges to C++. One common issue raised by people gravitates around designs where the choice of using iterators is long foregone, and would think that replacing iterators with ranges throughout should just work. Take a look: http://article.gmane.org/gmane.comp.lib.boost.devel/191978 The reality is algorithms implemented with ranges look different from algorithms implemented with iterators. Similarly, generic code with D will look different from generic code with C++. Our hope is, of course, that all told range-based and D-generics code has advantages going for it, but the most dramatic of those advantages most certainly won't be discovered and reaped in designs that are copies of the respective C++ ones.I'm not writing ranges or generics. Those things are fine, and they are also self-contained within D. I obviously use D completely differently to you, and value an entirely different set of features. Trust me, I'm not copying designs from C++, I use D specifically for use cases where C++ is utterly impotent. For me, 80% of generic code is about binding things (and a further 15% gamedev for the ecosystem to be made of (at least) 3 significant languages. Bindings are traditionally cumbersome, brittle, and one of the biggest hassles, frustrations, sources of time/productivity loss using C++ for game tech, is maintaining such bindings. D is the only language I know powerful enough to automate that mess. This is why D was attractive to me, and it is still why D is attractive to me. I _can't escape ref_ when writing this sort of code, and I write a lot of it. I don't think it's at all fair to say "I'm using D wrong", or "stop trying to be a C++ user in D", that's not the case here.. It's also a bit strange to hear you say all this when the key focus of development at the moment is "C++, GC", "C++, GC".So you can't be that weird and neither is your friend, but I speculate that both of you have a solid C++ background :o).No, I think we're pretty normal, and populace.About this situation in particular, yes, ref being part of the type does help this declaration, but overall as a design decision for the C++ programming value its value is questionable. T& is not a first class type and that hurts everyone everywhere - you can't create a value of that types, and virtually all parts of the language have special rules telling what happens when the actual type is a reference type.You're saying T& is not a first-class type and hurts everyone everywhere, I agree, and D is no different, except it is even worse. I'd like to explore ref as a first-class type. Do you have reason to believe that's completely unworkable? I'm not suggesting to clone C++'s design. I think there's room for a design that improves on C++.I think Walter made the right call here and we shouldn't change anything.This pretty much validates my opening suspicion. What do I do? STFU and deal with it? I suspect you'd think very differently if you worked with the people I do, have the conversations with colleagues I have, and struggled with the code I have for as long as I have. I dread to think how much ref has cost me in $/hr terms. You make ref sound worthless. Is there actually any situation where you find value in ref? If it's meaningless to you, and so 'un-D', why not let it have useful meaning for those who find it significant, important even? :/
Sep 29 2014
Manu:Trouble for me is, I've invested so much time now.If your think your choice was the wrong one, don't invest even more in something you think is wasted effort. Otherwise if you like D, then try to improve it from the inside, writing dmd/Phobos/druntime pull requests, instead of doing it from the outside.I find myself in a very awkward situation where I'm too far in... I can't go back to C++,Have you taken a look at Rust? Bye, bearophile
Sep 29 2014
On 30 September 2014 10:29, bearophile via Digitalmars-d <digitalmars-d puremagic.com> wrote:Manu:It's not to say it's the 'wrong choice'. I'm definitely an early adopter by nature, and in the case of D, I backed the only horse than I found realistic to solve my industry's chronic abuse. Perhaps I was being unrealistic when I thought I'd be able to get more colleagues on board than I have? It's just super annoying when the things that send them running are so bloody trivial! (although, apparently important) In the case of ref, I can't think of any programmers that I've introduced to D that haven't complained about ref within their first hour or 2 of interaction. I certainly hit the wall with ref within hours of contact with D, and 6 years later, it's exactly as bad as it was within those first few hours. The biggest issue inhibiting people getting on board though, by far, Practical issues > language issues.Trouble for me is, I've invested so much time now.If your think your choice was the wrong one, don't invest even more in something you think is wasted effort.Otherwise if you like D, then try to improve it from the inside, writing dmd/Phobos/druntime pull requests, instead of doing it from the outside.I'd never have my PR's pulled. I'm also not as interested in language development as it might appear. I'm interested in writing code and getting work done, and minimising friction. I'm interested in more efficient ways to get my work done, and also opportunities to write more efficient code, but that doesn't mean I want to stop doing my work and instead work on HOW I do my work.Yeah, it's just too weird for me to find realistic. It also more rigidly asserts it's opinions on you, which are in many cases, not optimal. Rust typically shows a performance disadvantage, which I care about. Perhaps more importantly, for practical reasons, I can't ever imagine convincing a studio of hundreds of programmers to switch to rust. C++ programmers can learn D by osmosis, but staff retraining burden to move to Rust seems completely unrealistic to me.I find myself in a very awkward situation where I'm too far in... I can't go back to C++,Have you taken a look at Rust?
Sep 29 2014
Manu:In the case of ref, I can't think of any programmers that I've introduced to D that haven't complained about ref within their first hour or 2 of interaction.Most of the times I have no problems with D ref. Perhaps you are trying to use D too much like you use C++.I'd never have my PR's pulled."Working from the inside" also means writing patches that have a sufficiently high probability of getting pulled after some changes and improvements.I'm also not as interested in language development as it might appear.Yet you discuss about language design all the time. I've discussed a lot about D, but often the topics that I have a bit more reliable opinions on are only the ones where I have direct experience (like Ranges). That's why I have suggested to write patches. With them you may be able to refine your own opinions about D.Yeah, it's just too weird for me to find realistic.I don't see it so much weird. It's a lot like a C crossed with the most obvious and simplified parts of ML, plus memory areas tracking, and small bits from Erlang and C++ and little more. It contains only small amounts of OOP, exceptions and GC, and currently its generics are still first order only, so it looks simple and coesive. I think an average programmer can learn it enough to be productive for single-thread user code (not for library code) in two or three months or less. But I think you should not even try to use it as you use Ada (unlike D). Bye, bearophile
Sep 29 2014
Otherwise if you like D, then try toYou're a vital alternative voice, please try to stick with us. The interest your talk and presence generated for D was huge and the games industry should be a major target for D. I also suspect Andrei is doing a major project at the moment which is making him uncharacteristically harsh in his responses, from his POV he's doing something massive to help D while the community has gone into a negative mode. I'm surprised at the lack of importance insufficient control over ref seems to be given, though my understanding is pretty basic. It feels a little similar to inlining. It might be an effective argument to give bearophile some of the problematic code and see what his idiomatic D version looks like and if what you're after is elegantly achievable. Clunky code would seem like a stronger argument at this point after many words have been exchanged. I think people are not really aware of the issues and if they believe the things are truly achievable with the language as it stands they can demonstrate it, with benchmarks etc.improve it from the inside, writing dmd/Phobos/druntime pull requests, instead of doing it from the outside.I'd never have my PR's pulled. I'm also not as interested in language development as it might appear. I'm interested in writing code and getting work done, and minimising friction. I'm interested in more efficient ways to get my work done, and also opportunities to write more efficient code, but that doesn't mean I want to stop doing my work and instead work on HOW I do my work.Yeah, it's just too weird for me to find realistic. It also more rigidly asserts it's opinions on you, which are in many cases, not optimal. Rust typically shows a performance disadvantage, which I care about. Perhaps more importantly, for practical reasons, I can't ever imagine convincing a studio of hundreds of programmers to switch to rust. C++ programmers can learn D by osmosis, but staff retraining burden to move to Rust seems completely unrealistic to me.I find myself in a very awkward situation where I'm too far in... I can't go back to C++,Have you taken a look at Rust?
Sep 30 2014
On Tuesday, 30 September 2014 at 09:13:02 UTC, ixid wrote:+10 <3 Pardon the pandering, but I actually see Andrei Walter and you as making up the trinity of idealism, codegen pragmatism and industry use respectively.Otherwise if you like D, then try toYou're a vital alternative voice, please try to stick with us. The interest your talk and presence generated for D was huge and the games industry should be a major target for D. I also suspect Andrei is doing a major project at the moment which is making him uncharacteristically harsh in his responses, from his POV he's doing something massive to help D while the community has gone into a negative mode.improve it from the inside, writing dmd/Phobos/druntime pull requests, instead of doing it from the outside.I'd never have my PR's pulled. I'm also not as interested in language development as it might appear. I'm interested in writing code and getting work done, and minimising friction. I'm interested in more efficient ways to get my work done, and also opportunities to write more efficient code, but that doesn't mean I want to stop doing my work and instead work on HOW I do my work.Yeah, it's just too weird for me to find realistic. It also more rigidly asserts it's opinions on you, which are in many cases, not optimal. Rust typically shows a performance disadvantage, which I care about. Perhaps more importantly, for practical reasons, I can't ever imagine convincing a studio of hundreds of programmers to switch to rust. C++ programmers can learn D by osmosis, but staff retraining burden to move to Rust seems completely unrealistic to me.I find myself in a very awkward situation where I'm too far in... I can't go back to C++,Have you taken a look at Rust?
Sep 30 2014
On 9/30/14, 2:13 AM, ixid wrote:from his POV he's doing something massive to help D while the community has gone into a negative mode.Indeed that's an accurate characterization of my POV. -- Andrei
Sep 30 2014
ixid:It might be an effective argument to give bearophile some of the problematic code and see what his idiomatic D version looks like and if what you're after is elegantly achievable.Manu is quite more expert than me in the kind of code he writes. So what you propose is just going to show my limits/ignorance... Bye, bearophile
Sep 30 2014
On Tuesday, 30 September 2014 at 09:13:02 UTC, ixid wrote:I also suspect Andrei is doing a major project at the moment which is making him uncharacteristically harsh in his responses, from his POV he's doing something massive to help D while the community has gone into a negative mode.There are only two kinds of languages: the ones people complain about and the ones nobody uses. The "negative mode" will likely become more negative as D continues to grow in popularity.
Sep 30 2014
On 9/30/2014 2:13 AM, ixid wrote:It might be an effective argument to give bearophile some of the problematic code and see what his idiomatic D version looks like and if what you're after is elegantly achievable.Or heck, ask the n.g. Lots of people here are very creative in their solutions to various D problems. You've shown me code that is essentially "I want to do XYZ with ref" but it's still at a low level - step up a layer or two.
Sep 30 2014
On Tuesday, 30 September 2014 at 00:03:40 UTC, Manu via Digitalmars-d wrote:I've affected all of the change that I am capable of, and I need to decide if I'm happy with D as is, or not, rather than maintain my ambient frustration that it's sitting at 99%, with the last 1% unattainable to me unless I fork the language for my own use :/Try to add some rudimentary support for ref in the compiler yourself? It is not a big semantic change (it is only pointers after all).
Sep 30 2014
On Tuesday, 30 September 2014 at 11:45:37 UTC, Ola Fosheim Grøstad wrote:(it is only pointers after all).Semi-tangential to this discussion, but this bit hits on something I've been thinking for a little while... ref is, at its core, trying to be a non-nullable pointer. And I get the strong sense that it's failing at it. -Wyatt
Sep 30 2014
On Tuesday, 30 September 2014 at 13:08:57 UTC, Wyatt wrote:Semi-tangential to this discussion, but this bit hits on something I've been thinking for a little while... ref is, at its core, trying to be a non-nullable pointer. And I get the strong sense that it's failing at it.That's a very perceptive observation. :) So you also get a sense that D could have non-nullable reference semantics for a ref-type? And possibly extend it to be assignable as a const-mutable-reference (pointer) using a dedicated operator or using the more ugly "&" notation or a cast? In Simula you had two assignment operators that made the the ref/value issue visually distinct. a :- b; //a points to b x := y; // x is assigned value of y It is analogue to the "==" vs "is" distinction that many languages make. I think it makes sense to have that visual distinction. Makes code easier to browse.
Sep 30 2014