digitalmars.D - So what does (inout int = 0) do?
- Andrei Alexandrescu (18/18) Apr 14 2016 Consider:
- Vladimir Panteleev (12/21) Apr 14 2016 I heard that sometimes git blame can track moving data between
- Jonathan M Davis via Digitalmars-d (18/36) Apr 14 2016 IIRC, the problem has to do with ranges of inout elements working correc...
- Andrei Alexandrescu (4/47) Apr 14 2016 I think we should deprecate inout. For real. It costs way too much for
- Vladimir Panteleev (10/13) Apr 14 2016 What would replace it in the case of classes, where you can't
- Andrei Alexandrescu (12/23) Apr 15 2016 You write several one-liners that forward to an internal template
- Guillaume Piolat (6/9) Apr 15 2016 This is the explanation I came up with, not sure if accurate. And
- Kenji Hara via Digitalmars-d (17/75) Apr 15 2016 You should recall the history of inout.
- Andrei Alexandrescu (9/23) Apr 15 2016 I do recall the history. The enhancement is sensible in a frame of mind
- Kenji Hara via Digitalmars-d (15/44) Apr 15 2016 Didn't you use array.dup until now? It's a good example to handle
- Andrei Alexandrescu (25/37) Apr 15 2016 What are a few examples of the power of inout?
- jmh530 (6/10) Apr 15 2016 If it's something to be avoided except in particular cases, then
- Andrei Alexandrescu (3/5) Apr 15 2016 The main reason is actually avoiding code duplication is such situations...
- Steven Schveighoffer (59/91) Apr 15 2016 T[] dup(T)(T[] arr)
- Andrei Alexandrescu (39/117) Apr 15 2016 A better support for this argument is std.array.replaceSlice at
- Steven Schveighoffer (23/128) Apr 15 2016 You can add more flexibility and keep inout at the same time. The nice
- Andrei Alexandrescu (9/26) Apr 15 2016 Problem is we could have other problems once we fix those. As you just
- Steven Schveighoffer (14/27) Apr 15 2016 If you look at the core of what inout actually is (a type modifier
- QAston (5/10) Apr 17 2016 This deserves to be a poster with a golden frame. You've got
- Nick Treleaven (14/17) Apr 17 2016 The @safe troika is a good design (except @safe should be the
- QAston (21/35) Apr 17 2016 Yeah, but for example rust deals with the same problem with a
- ag0aep6g (15/19) Apr 17 2016 @property is in a bad state right now. The behavior that used to be
- Kagamin (4/9) Apr 19 2016 Rationale behind DIP23 seems to make language usable without
- Timon Gehr (10/11) Apr 17 2016 No, it isn't:
- Adam D. Ruppe (5/8) Apr 17 2016 Seriously, @property is one of the biggest SNAFUs of the language.
- Temtaime (3/13) Apr 17 2016 nothrow may be useful for passing callbacks in C functions.
- Kagamin (3/4) Apr 19 2016 shared did catch bugs in phobos and user code, that would
- deadalnix (2/9) Apr 17 2016 Today I learned a new acronym. Fit @property perfectly.
- Guillaume Piolat (13/23) Apr 18 2016 As a big user of @nogc, I'd disagree. @nogc is a bit hard to use
- Guillaume Piolat (3/6) Apr 18 2016 And shared and @property :)
- Adam D. Ruppe (4/5) Apr 18 2016 I still want to see @property fixed rather than removed - the
- Marc =?UTF-8?B?U2Now7x0eg==?= (10/17) Apr 16 2016 (It seems my reply got lost somewhere, reposting...)
- Nick Treleaven (5/11) Apr 16 2016 AIUI, functions don't have to return part of the parameter tagged with
- Marc =?UTF-8?B?U2Now7x0eg==?= (6/23) Apr 18 2016 I'm not sure. That section says that the situation may change in
- Dmitry Olshansky (6/15) Apr 15 2016 Love this trend! inout is a monstrously complicated feature solving
- Jacob Carlborg (25/28) Apr 16 2016 If "inout" is only used as a way avoid code duplication, both when
- deadalnix (2/11) Apr 15 2016 Whatever the problem is, none of this seems like a good solution.
- Andrei Alexandrescu (2/13) Apr 15 2016 I agree. -- Andrei
- Nick Treleaven (8/15) Apr 15 2016 Assuming it works OK, that seems much cleaner:
- Andrei Alexandrescu (6/22) Apr 15 2016 That makes other unittests fail (those with noncopyable ranges).
- Shammah Chancellor (10/32) Apr 14 2016 `(int inout = 0)` is not the only problem with that template --
- Andrei Alexandrescu (2/4) Apr 15 2016 No. -- Andrei
- Walter Bright (2/5) Apr 14 2016 https://issues.dlang.org/show_bug.cgi?id=15926
- w0rp (10/10) Apr 15 2016 I think it has something to do with making the function, in this
- w0rp (9/19) Apr 15 2016 To clarify my example. My problem was that I had a container
- Andrei Alexandrescu (5/11) Apr 15 2016 Nice, thanks. I think I can put a finger on what bothers me the most:
- Timon Gehr (26/39) Apr 15 2016 Related: Phobos should never use is(typeof(...)). Contrary to popular
- Timon Gehr (3/6) Apr 15 2016 inout disallows
- Adam D. Ruppe (13/16) Apr 15 2016 I don't think it should be using __traits(compiles) either. I'd
- Andrei Alexandrescu (3/5) Apr 15 2016 I agree. The more I try things with it the more awfully complex and
- Marco Leise (8/8) Apr 16 2016 Am Fri, 15 Apr 2016 09:44:05 -0400
- Lass Safin (3/8) Apr 16 2016 What does that have to do with what he said?
- ixid (4/9) Apr 15 2016 Why didn't we go with all functions being able to infer const,
- Guillaume Piolat (3/5) Apr 15 2016 Non-templated function may not have their source code available.
- deadalnix (4/16) Apr 15 2016 The problem is essentially untractable when there are loops in
- QAston (4/10) Apr 15 2016 I've been wondering what that is myself, so I've just
- Steven Schveighoffer (13/15) Apr 15 2016 It works around a limitation of inout that isn't necessary (even though
- Timon Gehr (15/34) Apr 15 2016 That's potentially dangerous. What about cases like the following?
- Steven Schveighoffer (23/58) Apr 15 2016 We don't need to guess:
- Andrei Alexandrescu (3/7) Apr 15 2016 Another special case? The only correct thing is to simplify the language...
- Steven Schveighoffer (8/16) Apr 15 2016 This is not a special case any more than disallowing access of shared
- Timon Gehr (16/83) Apr 15 2016 I'm very aware of that: https://issues.dlang.org/show_bug.cgi?id=10758
- Steven Schveighoffer (15/102) Apr 15 2016 There's no difference between a function that declares its variables
- Andrei Alexandrescu (9/11) Apr 15 2016 So now we get to things like:
- Timon Gehr (4/15) Apr 15 2016 It's an int that has not decided yet whether it wants to be mutable,
- Timon Gehr (11/124) Apr 15 2016 Yes, there is. Semantic analysis sees the parameter types before it sees...
- Andrei Alexandrescu (3/7) Apr 15 2016 Nicely put on both counts. (Well "real" is semantically sarcastic a
- Steven Schveighoffer (29/52) Apr 15 2016 I don't know what the current implementation sees the function as doing....
- Timon Gehr (18/82) Apr 15 2016 That's sensible, of course. The current implementation is a lot more
- Steven Schveighoffer (23/56) Apr 15 2016 I'm sorry, should have put on my standard disclaimer that I am not a
- Seb (5/12) May 01 2016 inout(bool) newsgroup.revive_discussion();
- Steven Schveighoffer (4/17) May 02 2016 If we can find a way to replace inout with something that does
- Nick Treleaven (12/17) Apr 16 2016 Perhaps use this, at least for now:
Consider: https://github.com/D-Programming-Language/phobos/blob/master/std/range/primitives.d#L152 There is no explanation to it in the source code, and the line blames to https://github.com/D-Programming-Language/phobos/pull/2661 (irrelevant). Commenting it out yields a number of unittest compilation errors, neither informative about the root of the problem and indicative as to how the parameter solves it. There are two issues here: 1. Once a problem/solution pair of this degree of subtlety crops up, we need to convince ourselves that that's sensible. If we deem it not so, we look into improving the language to make the problem disappear. 2. There needs to be documentation for people working on the standard library so they don't need to waste time on their own discovery process. We want Phobos to be beautiful, a prime example of good D code. Admittedly, it also needs to be very general and efficient, which sometimes gets in the way. But we cannot afford an accumulation of mad tricks to obscure the large design. Andrei
Apr 14 2016
On Friday, 15 April 2016 at 03:10:12 UTC, Andrei Alexandrescu wrote:Consider: https://github.com/D-Programming-Language/phobos/blob/master/std/range/primitives.d#L152 There is no explanation to it in the source code, and the line blames to https://github.com/D-Programming-Language/phobos/pull/2661 (irrelevant).I heard that sometimes git blame can track moving data between files, but this is not such a case. You can continue the blame by blaming the old path starting from the commit preceding that one: git blame c828a08b64de067eeb2ddcad8fed22b2cd92e438^ -- range.dCommenting it out yields a number of unittest compilation errors, neither informative about the root of the problem and indicative as to how the parameter solves it.I'm not sure what errors you saw but the first one is that this fails: static assert( isInputRange!(inout(int)[])); git blame on this line points to: https://issues.dlang.org/show_bug.cgi?id=7824
Apr 14 2016
On Thursday, April 14, 2016 23:10:12 Andrei Alexandrescu via Digitalmars-d wrote:Consider: https://github.com/D-Programming-Language/phobos/blob/master/std/range/primi tives.d#L152 There is no explanation to it in the source code, and the line blames to https://github.com/D-Programming-Language/phobos/pull/2661 (irrelevant). Commenting it out yields a number of unittest compilation errors, neither informative about the root of the problem and indicative as to how the parameter solves it. There are two issues here: 1. Once a problem/solution pair of this degree of subtlety crops up, we need to convince ourselves that that's sensible. If we deem it not so, we look into improving the language to make the problem disappear. 2. There needs to be documentation for people working on the standard library so they don't need to waste time on their own discovery process. We want Phobos to be beautiful, a prime example of good D code. Admittedly, it also needs to be very general and efficient, which sometimes gets in the way. But we cannot afford an accumulation of mad tricks to obscure the large design.IIRC, the problem has to do with ranges of inout elements working correctly, which gets really funky, because inout is a temporary thing and not a full-on type constructor/qualifier. I believe that Kenji is the one that implemented the fix, and I think that he explained it in the newsgroup at some point. Certainly, there have been a few times that it's come up in D.Learn when folks ask what the heck it is, so there should be a few posts floating around with an explanation. This is the only useful post that I could find in a quick search though: http://forum.dlang.org/post/mh68p8$2p56$1 digitalmars.com inout attempts to solve a very real problem, but it does seem to be surprisingly hard to understand and use prooperly even though it's theoretically simple. And this bit with ranges is a quirk that I think very few people understand and remember. I usually forget exactly what it does when it comes up and have to try and dig through the newsgroup archives for a previous discussion on it. - Jonathan M Davis
Apr 14 2016
On 04/15/2016 12:23 AM, Jonathan M Davis via Digitalmars-d wrote:On Thursday, April 14, 2016 23:10:12 Andrei Alexandrescu via Digitalmars-d wrote:I think we should deprecate inout. For real. It costs way too much for what it does. For all I can tell most of D's proponents don't know how it works. -- AndreiConsider: https://github.com/D-Programming-Language/phobos/blob/master/std/range/primi tives.d#L152 There is no explanation to it in the source code, and the line blames to https://github.com/D-Programming-Language/phobos/pull/2661 (irrelevant). Commenting it out yields a number of unittest compilation errors, neither informative about the root of the problem and indicative as to how the parameter solves it. There are two issues here: 1. Once a problem/solution pair of this degree of subtlety crops up, we need to convince ourselves that that's sensible. If we deem it not so, we look into improving the language to make the problem disappear. 2. There needs to be documentation for people working on the standard library so they don't need to waste time on their own discovery process. We want Phobos to be beautiful, a prime example of good D code. Admittedly, it also needs to be very general and efficient, which sometimes gets in the way. But we cannot afford an accumulation of mad tricks to obscure the large design.IIRC, the problem has to do with ranges of inout elements working correctly, which gets really funky, because inout is a temporary thing and not a full-on type constructor/qualifier. I believe that Kenji is the one that implemented the fix, and I think that he explained it in the newsgroup at some point. Certainly, there have been a few times that it's come up in D.Learn when folks ask what the heck it is, so there should be a few posts floating around with an explanation. This is the only useful post that I could find in a quick search though: http://forum.dlang.org/post/mh68p8$2p56$1 digitalmars.com inout attempts to solve a very real problem, but it does seem to be surprisingly hard to understand and use prooperly even though it's theoretically simple. And this bit with ranges is a quirk that I think very few people understand and remember. I usually forget exactly what it does when it comes up and have to try and dig through the newsgroup archives for a previous discussion on it. - Jonathan M Davis
Apr 14 2016
On Friday, 15 April 2016 at 05:38:56 UTC, Andrei Alexandrescu wrote:I think we should deprecate inout. For real. It costs way too much for what it does. For all I can tell most of D's proponents don't know how it works. -- AndreiWhat would replace it in the case of classes, where you can't have templated virtual methods? Perhaps a mechanism to declare a templated virtual function, and a list of instantiations which will go into the vtable? If we are to kill inout and replace it with something else, then it should support cases where inout failed, such as inout on the parameter of a delegate passed to the function (see: inout opApply).
Apr 14 2016
On 04/15/2016 02:15 AM, Vladimir Panteleev wrote:On Friday, 15 April 2016 at 05:38:56 UTC, Andrei Alexandrescu wrote:You write several one-liners that forward to an internal template implementation.I think we should deprecate inout. For real. It costs way too much for what it does. For all I can tell most of D's proponents don't know how it works. -- AndreiWhat would replace it in the case of classes, where you can't have templated virtual methods? Perhaps a mechanism to declare a templated virtual function, and a list of instantiations which will go into the vtable?If we are to kill inout and replace it with something else, then it should support cases where inout failed, such as inout on the parameter of a delegate passed to the function (see: inout opApply).I think we should kill it, period. No replacement is really needed, for the most part most problems with inout are complications caused by the very presence of inout. C++ has no parameterization of qualifiers and lived with it like a guy lives with a bald spot on a butt cheek. There's not even a proposal I can remember to fix that. Those duplications are the least of C++'s, or any langauge's, problems. inout must go. Andrei
Apr 15 2016
On Friday, 15 April 2016 at 05:38:56 UTC, Andrei Alexandrescu wrote:I think we should deprecate inout. For real. It costs way too much for what it does. For all I can tell most of D's proponents don't know how it works. -- AndreiThis is the explanation I came up with, not sure if accurate. And only to teach myself the basics. https://p0nce.github.io/d-idioms/#Knowing-inout-inside-out I'm all for removing things!
Apr 15 2016
2016-04-15 14:38 GMT+09:00 Andrei Alexandrescu via Digitalmars-d < digitalmars-d puremagic.com>:On 04/15/2016 12:23 AM, Jonathan M Davis via Digitalmars-d wrote:You should recall the history of inout. http://wiki.dlang.org/DIP2 At first, It has designed to temporarily squash mutable/const/immutable qualifiers on function argument inside function body. Therefore when inout qualifier appears in function return type, but doesn't on parameter types, we defined it an error. However, I concluded that we can remove the restriction. When an inout object arises from thin air, no one holds the qualifier of its real instance. It means, the returned inout object can be converted to arbitrary qualifiers without type system breaking. Two years ago I opened an enhancement issue: https://issues.dlang.org/show_bug.cgi?id=13006 And posted a pull request. https://github.com/D-Programming-Language/dmd/pull/3740 Kenji HaraOn Thursday, April 14, 2016 23:10:12 Andrei Alexandrescu via Digitalmars-d wrote:I think we should deprecate inout. For real. It costs way too much for what it does. For all I can tell most of D's proponents don't know how it works. -- AndreiConsider: https://github.com/D-Programming-Language/phobos/blob/master/std/range/primi tives.d#L152 There is no explanation to it in the source code, and the line blames to https://github.com/D-Programming-Language/phobos/pull/2661 (irrelevant). Commenting it out yields a number of unittest compilation errors, neither informative about the root of the problem and indicative as to how the parameter solves it. There are two issues here: 1. Once a problem/solution pair of this degree of subtlety crops up, we need to convince ourselves that that's sensible. If we deem it not so, we look into improving the language to make the problem disappear. 2. There needs to be documentation for people working on the standard library so they don't need to waste time on their own discovery process. We want Phobos to be beautiful, a prime example of good D code. Admittedly, it also needs to be very general and efficient, which sometimes gets in the way. But we cannot afford an accumulation of mad tricks to obscure the large design.IIRC, the problem has to do with ranges of inout elements working correctly, which gets really funky, because inout is a temporary thing and not a full-on type constructor/qualifier. I believe that Kenji is the one that implemented the fix, and I think that he explained it in the newsgroup at some point. Certainly, there have been a few times that it's come up in D.Learn when folks ask what the heck it is, so there should be a few posts floating around with an explanation. This is the only useful post that I could find in a quick search though: http://forum.dlang.org/post/mh68p8$2p56$1 digitalmars.com inout attempts to solve a very real problem, but it does seem to be surprisingly hard to understand and use prooperly even though it's theoretically simple. And this bit with ranges is a quirk that I think very few people understand and remember. I usually forget exactly what it does when it comes up and have to try and dig through the newsgroup archives for a previous discussion on it. - Jonathan M Davis
Apr 15 2016
On 04/15/2016 06:50 AM, Kenji Hara via Digitalmars-d wrote:You should recall the history of inout. http://wiki.dlang.org/DIP2 At first, It has designed to temporarily squash mutable/const/immutable qualifiers on function argument inside function body. Therefore when inout qualifier appears in function return type, but doesn't on parameter types, we defined it an error. However, I concluded that we can remove the restriction. When an inout object arises from thin air, no one holds the qualifier of its real instance. It means, the returned inout object can be converted to arbitrary qualifiers without type system breaking. Two years ago I opened an enhancement issue: https://issues.dlang.org/show_bug.cgi?id=13006 And posted a pull request. https://github.com/D-Programming-Language/dmd/pull/3740I do recall the history. The enhancement is sensible in a frame of mind "we need to keep inout" but I'm looking at top level and thinking, crap we can put up with a little duplication if we get rid of inout. It's just a prime example of apparently simple idea gone bonkers. In all of my recent code I've avoided inout and didn't miss it one bit. There's no need for it - I replace it with one-liners that forward to template functions, which in turn deduce qualifiers and all is great. Andrei
Apr 15 2016
2016-04-15 22:41 GMT+09:00 Andrei Alexandrescu via Digitalmars-d < digitalmars-d puremagic.com>:On 04/15/2016 06:50 AM, Kenji Hara via Digitalmars-d wrote:Didn't you use array.dup until now? It's a good example to handle qualifiers with inout. It's not sensible at all, inout is already well-defined and has much power in D's type system. Removing it is just a foolish idea. If you worry the future of Phobos written in D, first you would need to think about safe. It's yet not well defined/implemented by compiler, and many Phobos code are marked as trusted. Does it has lower priority than complain to a small hack for the *current* inout limitation? I just cannot agree your argument. Kenji HaraYou should recall the history of inout. http://wiki.dlang.org/DIP2 At first, It has designed to temporarily squash mutable/const/immutable qualifiers on function argument inside function body. Therefore when inout qualifier appears in function return type, but doesn't on parameter types, we defined it an error. However, I concluded that we can remove the restriction. When an inout object arises from thin air, no one holds the qualifier of its real instance. It means, the returned inout object can be converted to arbitrary qualifiers without type system breaking. Two years ago I opened an enhancement issue: https://issues.dlang.org/show_bug.cgi?id=13006 And posted a pull request. https://github.com/D-Programming-Language/dmd/pull/3740I do recall the history. The enhancement is sensible in a frame of mind "we need to keep inout" but I'm looking at top level and thinking, crap we can put up with a little duplication if we get rid of inout. It's just a prime example of apparently simple idea gone bonkers. In all of my recent code I've avoided inout and didn't miss it one bit. There's no need for it - I replace it with one-liners that forward to template functions, which in turn deduce qualifiers and all is great.
Apr 15 2016
On 04/15/2016 12:19 PM, Kenji Hara via Digitalmars-d wrote:Didn't you use array.dup until now? It's a good example to handle qualifiers with inout.Would it be difficult to make it work without inout?It's not sensible at all, inout is already well-defined and has much power in D's type system. Removing it is just a foolish idea.What are a few examples of the power of inout? What things does inout afford us, that would be otherwise not achievable?If you worry the future of Phobos written in D, first you would need to think about safe. It's yet not well defined/implemented by compiler, and many Phobos code are marked as trusted. Does it has lower priority than complain to a small hack for the *current* inout limitation?The thing about safe is it does enable things that otherwise would not be possible. Overall I agree there are plenty of things that deserve a revisit, but just putting in competition things against one another is unlikely to shed light on their technical merit.I just cannot agree your argument.I understand and would like to be better informed. So could you please substantiate your argument by replying to the questions above? To restate my arguments: 1. The motivation of inout is clear and simple - have it as a placeholder for any other qualifier so as to avoid the method duplication observed in C++. However, it has over time grown into a feature of which complexity way transcends its small usefulness. 2. Attempting to make inout useful have created their own problems, solving which in turn have increased its complexity. This cycle of accretions has led over time to a vortex of oddity in the middle of the type system. 3. For all problems that inout is purported to solve, I know of idioms that are definitely simpler and overall almost as good if not better. So a hard question is whether the existence is justified. There are 306 uses of inout in Phobos. A good thing to do would be an investigation of their usefulness. Andrei
Apr 15 2016
On Friday, 15 April 2016 at 17:11:39 UTC, Andrei Alexandrescu wrote:3. For all problems that inout is purported to solve, I know of idioms that are definitely simpler and overall almost as good if not better. So a hard question is whether the existence is justified.If it's something to be avoided except in particular cases, then I suggest that is made clear in the documentation. I had not realized that the main reason that inout was added was because of not being able to use templates as virtual functions in classes.
Apr 15 2016
On 04/15/2016 02:24 PM, jmh530 wrote:I had not realized that the main reason that inout was added was because of not being able to use templates as virtual functions in classes.The main reason is actually avoiding code duplication is such situations (i.e. the problem has a solution just not ideal). -- Andrei
Apr 15 2016
On 4/15/16 1:11 PM, Andrei Alexandrescu wrote:On 04/15/2016 12:19 PM, Kenji Hara via Digitalmars-d wrote:T[] dup(T)(T[] arr) this should be doable. Problem is, you get identical instantiations for each of the different qualifiers, unless you take different actions based on the mutability. Instead: inout(T)[] dup(T)(inout(T)[] arr) This is one instantiation, no matter the mutability of the parameter. And it guarantees no molestation of arr, even if it's mutable. This would be much more difficult with a struct/class, whereas with inout it's pretty simple. But I think dup as it is defined is a bad example, because as defined by the language, it implies that you want a mutable version where the source may be const/immutable. In the general sense, a duplication function where you get the *same* mutability is more applicable for inout.Didn't you use array.dup until now? It's a good example to handle qualifiers with inout.Would it be difficult to make it work without inout?One thing to understand is that inout is only valuable if you think const is valuable. That is, you think the advertisement of "no, I will not modify this parameter, give me whatever you got" is of value. If you don't care, then templates suffice. void popFront(T)(inout(T)[] arr) This is possible only with inout. const will not cut it. The current definition is: void popFront(T)(T[] arr) which is OK, but there is no advertisement that popFront doesn't change any data in arr.It's not sensible at all, inout is already well-defined and has much power in D's type system. Removing it is just a foolish idea.What are a few examples of the power of inout?What things does inout afford us, that would be otherwise not achievable?advertisement of const without having to cast the type to const (and all the limitations that entail).I think the point of Kenji's argument is that inout's current limitations are what you are bumping into, and those limitations are unnecessary and arbitrary. We can make inout better and more consistent. Pretty easily actually. We can certainly fix the inout int = 0 problem.If you worry the future of Phobos written in D, first you would need to think about safe. It's yet not well defined/implemented by compiler, and many Phobos code are marked as trusted. Does it has lower priority than complain to a small hack for the *current* inout limitation?The thing about safe is it does enable things that otherwise would not be possible. Overall I agree there are plenty of things that deserve a revisit, but just putting in competition things against one another is unlikely to shed light on their technical merit.To restate my arguments: 1. The motivation of inout is clear and simple - have it as a placeholder for any other qualifier so as to avoid the method duplication observed in C++. However, it has over time grown into a feature of which complexity way transcends its small usefulness.It has some rough edges. These can be smoothed out.2. Attempting to make inout useful have created their own problems, solving which in turn have increased its complexity. This cycle of accretions has led over time to a vortex of oddity in the middle of the type system.This is not what you are railing against. The current limitations (and their workarounds) are self-imposed, we just need to get rid of them. An interesting thing is that when you involve generic code, certain "good ideas" become very inconvenient. For example, this whole discussion is based on the idea that "if you don't have any inout parameters, why are you declaring inout variables? It makes no sense!" A very sensible and logical idea. But when you want code that works with or without inout variables, all of a sudden the same code is throwing an error in some cases because of an unforeseen situation. Another example is code like this: int firstInt(T...)(T t) { foreach(ref x; t) { static if(typeof(x) == int) return x; } return -1; } This throws an error because if there is an int in T..., then return -1 statement is "unreachable". This is similar to the inout int = 0 case. In non-generic code, it makes sense to flag code that won't be reached. But in generic code, it's actually not a true statement for all instantiations of the template! It's another limitation we should relax.3. For all problems that inout is purported to solve, I know of idioms that are definitely simpler and overall almost as good if not better. So a hard question is whether the existence is justified.I know of no "better" idioms, in terms of code generation and specificity, to replace inout (or at least, inout as I envision it should be). Care to elaborate? -Steve
Apr 15 2016
On 4/15/16 2:39 PM, Steven Schveighoffer wrote:On 4/15/16 1:11 PM, Andrei Alexandrescu wrote:A better support for this argument is std.array.replaceSlice at https://github.com/D-Programming-Language/phobos/blob/master/std/array.d#L2594: inout(T)[] replaceSlice(T)(inout(T)[] s, in T[] slice, in T[] replacement); So here we are guaranteed that (a) the result type is the same as the first argument, and (b) the first argument is never modified even if a mutable slice is passed. I agree this is a nice property, and one that C++ does not enjoy. The questions are of course how important it is, how useful it is, and what price it is worth. Getting back to replaceSlice I'd define it in more flexible terms anyway. So I'd eliminate the use of inout there even if it did add value.On 04/15/2016 12:19 PM, Kenji Hara via Digitalmars-d wrote:T[] dup(T)(T[] arr) this should be doable. Problem is, you get identical instantiations for each of the different qualifiers, unless you take different actions based on the mutability. Instead: inout(T)[] dup(T)(inout(T)[] arr) This is one instantiation, no matter the mutability of the parameter. And it guarantees no molestation of arr, even if it's mutable. This would be much more difficult with a struct/class, whereas with inout it's pretty simple. But I think dup as it is defined is a bad example, because as defined by the language, it implies that you want a mutable version where the source may be const/immutable. In the general sense, a duplication function where you get the *same* mutability is more applicable for inout.Didn't you use array.dup until now? It's a good example to handle qualifiers with inout.Would it be difficult to make it work without inout?This is correct but incomplete. The omitted part is that inout is valuable when $EVERYTHING_YOU_SAID and also you want to transport the qualifier from an argument to the result. This diminishes its importance considerably for all folks, including those for whom const is important.One thing to understand is that inout is only valuable if you think const is valuable. That is, you think the advertisement of "no, I will not modify this parameter, give me whatever you got" is of value. If you don't care, then templates suffice.It's not sensible at all, inout is already well-defined and has much power in D's type system. Removing it is just a foolish idea.What are a few examples of the power of inout?void popFront(T)(inout(T)[] arr)void popFront(T)(ref inout(T)[] arr); (point stays)This is possible only with inout. const will not cut it. The current definition is: void popFront(T)(T[] arr) which is OK, but there is no advertisement that popFront doesn't change any data in arr.Should this work as well? void popFront(ref const(T)[] arr); In other words conversion of ref T[] to ref const(T)[] is sound.I'm not sure - at all in fact. This is at the tail of a sequence of changes of inout, and there is a history of such mini-designs leading to complications, regressions, and further mini-designs. It's the wolf that eats the dog that eats the cat that eats the mouse. We fix this and there's another and then another and then another. It has already happened. In fact Walter's and my design of inout is a prime example of the failings of that approach. We underdesigned it to work in a few small examples. We knew we lost when Kenji figured inout must be a type qualifier (we were hoping to getting away with it being a sort of a placeholder/wildcard). I think we should have pulled it back then. It's become a mini-monster that only wants more attention, more language changes, more work.What things does inout afford us, that would be otherwise not achievable?advertisement of const without having to cast the type to const (and all the limitations that entail).I think the point of Kenji's argument is that inout's current limitations are what you are bumping into, and those limitations are unnecessary and arbitrary. We can make inout better and more consistent. Pretty easily actually. We can certainly fix the inout int = 0 problem.If you worry the future of Phobos written in D, first you would need to think about safe. It's yet not well defined/implemented by compiler, and many Phobos code are marked as trusted. Does it has lower priority than complain to a small hack for the *current* inout limitation?The thing about safe is it does enable things that otherwise would not be possible. Overall I agree there are plenty of things that deserve a revisit, but just putting in competition things against one another is unlikely to shed light on their technical merit.An interesting thing is that when you involve generic code, certain "good ideas" become very inconvenient. For example, this whole discussion is based on the idea that "if you don't have any inout parameters, why are you declaring inout variables? It makes no sense!" A very sensible and logical idea. But when you want code that works with or without inout variables, all of a sudden the same code is throwing an error in some cases because of an unforeseen situation.This is an example of the mini-monster: the use of inout is necessary to satisfy the existence of inout.Another example is code like this: int firstInt(T...)(T t) { foreach(ref x; t) { static if(typeof(x) == int) return x; } return -1; } This throws an error because if there is an int in T..., then return -1 statement is "unreachable". This is similar to the inout int = 0 case.Not at all! There are very nice solutions for this, including looking at T or recursion. I think we can safely strike this one.I thought I did. Use one-liner functions that forward to templates. Andrei3. For all problems that inout is purported to solve, I know of idioms that are definitely simpler and overall almost as good if not better. So a hard question is whether the existence is justified.I know of no "better" idioms, in terms of code generation and specificity, to replace inout (or at least, inout as I envision it should be). Care to elaborate?
Apr 15 2016
On 4/15/16 3:28 PM, Andrei Alexandrescu wrote:On 4/15/16 2:39 PM, Steven Schveighoffer wrote:In fact, a mutable slice must be passed (slice is not marked as inout).On 4/15/16 1:11 PM, Andrei Alexandrescu wrote:A better support for this argument is std.array.replaceSlice at https://github.com/D-Programming-Language/phobos/blob/master/std/array.d#L2594: inout(T)[] replaceSlice(T)(inout(T)[] s, in T[] slice, in T[] replacement); So here we are guaranteed that (a) the result type is the same as the first argument, and (b) the first argument is never modified even if a mutable slice is passed.Would it be difficult to make it work without inout?T[] dup(T)(T[] arr) this should be doable. Problem is, you get identical instantiations for each of the different qualifiers, unless you take different actions based on the mutability. Instead: inout(T)[] dup(T)(inout(T)[] arr) This is one instantiation, no matter the mutability of the parameter. And it guarantees no molestation of arr, even if it's mutable. This would be much more difficult with a struct/class, whereas with inout it's pretty simple. But I think dup as it is defined is a bad example, because as defined by the language, it implies that you want a mutable version where the source may be const/immutable. In the general sense, a duplication function where you get the *same* mutability is more applicable for inout.I agree this is a nice property, and one that C++ does not enjoy. The questions are of course how important it is, how useful it is, and what price it is worth. Getting back to replaceSlice I'd define it in more flexible terms anyway. So I'd eliminate the use of inout there even if it did add value.You can add more flexibility and keep inout at the same time. The nice feature here is that inout protects the elements of s that aren't in slice, and there is no requirement to verify s and slice are the same underlying type, etc.Nope. Actually inout has proven to have a more interesting property of not requiring casting.One thing to understand is that inout is only valuable if you think const is valuable. That is, you think the advertisement of "no, I will not modify this parameter, give me whatever you got" is of value. If you don't care, then templates suffice.This is correct but incomplete. The omitted part is that inout is valuable when $EVERYTHING_YOU_SAID and also you want to transport the qualifier from an argument to the result. This diminishes its importance considerably for all folks, including those for whom const is important.Yes, thanks, that is what I meant.void popFront(T)(inout(T)[] arr)void popFront(T)(ref inout(T)[] arr); (point stays)No, because it's not sound. you cannot cast to const through 2+ indirections. However inout works there.This is possible only with inout. const will not cut it. The current definition is: void popFront(T)(T[] arr) which is OK, but there is no advertisement that popFront doesn't change any data in arr.Should this work as well? void popFront(ref const(T)[] arr); In other words conversion of ref T[] to ref const(T)[] is sound.I assure you, these limitations were self-imposed. I insisted on them, without realizing that they would cause problems with generic code. I thought they would be good "lint" detection. https://issues.dlang.org/show_bug.cgi?id=3748I think the point of Kenji's argument is that inout's current limitations are what you are bumping into, and those limitations are unnecessary and arbitrary. We can make inout better and more consistent. Pretty easily actually. We can certainly fix the inout int = 0 problem.I'm not sure - at all in fact. This is at the tail of a sequence of changes of inout, and there is a history of such mini-designs leading to complications, regressions, and further mini-designs. It's the wolf that eats the dog that eats the cat that eats the mouse. We fix this and there's another and then another and then another. It has already happened.In fact Walter's and my design of inout is a prime example of the failings of that approach. We underdesigned it to work in a few small examples. We knew we lost when Kenji figured inout must be a type qualifier (we were hoping to getting away with it being a sort of a placeholder/wildcard). I think we should have pulled it back then. It's become a mini-monster that only wants more attention, more language changes, more work.It must be a type qualifier or it doesn't work.I don't know what this argument is saying?An interesting thing is that when you involve generic code, certain "good ideas" become very inconvenient. For example, this whole discussion is based on the idea that "if you don't have any inout parameters, why are you declaring inout variables? It makes no sense!" A very sensible and logical idea. But when you want code that works with or without inout variables, all of a sudden the same code is throwing an error in some cases because of an unforeseen situation.This is an example of the mini-monster: the use of inout is necessary to satisfy the existence of inout.Absolutely similar. There are ways around it, but at the end of the day, the compiler is complaining that the line can never be reached, when in fact it can (just pass a short in). Just like there are ways around the inout local variable requirement.Another example is code like this: int firstInt(T...)(T t) { foreach(ref x; t) { static if(typeof(x) == int) return x; } return -1; } This throws an error because if there is an int in T..., then return -1 statement is "unreachable". This is similar to the inout int = 0 case.Not at all! There are very nice solutions for this, including looking at T or recursion. I think we can safely strike this one.I didn't see it? -SteveI thought I did. Use one-liner functions that forward to templates.3. For all problems that inout is purported to solve, I know of idioms that are definitely simpler and overall almost as good if not better. So a hard question is whether the existence is justified.I know of no "better" idioms, in terms of code generation and specificity, to replace inout (or at least, inout as I envision it should be). Care to elaborate?
Apr 15 2016
On 04/15/2016 03:44 PM, Steven Schveighoffer wrote:No, because it's not sound. you cannot cast to const through 2+ indirections. However inout works there.That is correct, a classic... thanks for getting me straight.Problem is we could have other problems once we fix those. As you just showed, it has already happened. We should really do away with the cowboy style of designing language, which sadly Walter and I have been guilty of too often in the past. The slow but sure accretion of complexity of inout is a textbook example of where that leads. AndreiI assure you, these limitations were self-imposed. I insisted on them, without realizing that they would cause problems with generic code. I thought they would be good "lint" detection. https://issues.dlang.org/show_bug.cgi?id=3748I think the point of Kenji's argument is that inout's current limitations are what you are bumping into, and those limitations are unnecessary and arbitrary. We can make inout better and more consistent. Pretty easily actually. We can certainly fix the inout int = 0 problem.I'm not sure - at all in fact. This is at the tail of a sequence of changes of inout, and there is a history of such mini-designs leading to complications, regressions, and further mini-designs. It's the wolf that eats the dog that eats the cat that eats the mouse. We fix this and there's another and then another and then another. It has already happened.
Apr 15 2016
On 4/15/16 4:03 PM, Andrei Alexandrescu wrote:On 04/15/2016 03:44 PM, Steven Schveighoffer wrote:If you look at the core of what inout actually is (a type modifier placeholder), we can simplify how to think about it, and how to implement it. These "requirements" were just extra helpful things that would flag valid, but (naively assumed) pointless code. Turns out, templates generate lots of pointless code (that is typically optimized away in the type system or the optimizer). I hope to make this clear in my talk at dconf.I assure you, these limitations were self-imposed. I insisted on them, without realizing that they would cause problems with generic code. I thought they would be good "lint" detection. https://issues.dlang.org/show_bug.cgi?id=3748Problem is we could have other problems once we fix those. As you just showed, it has already happened.We should really do away with the cowboy style of designing language, which sadly Walter and I have been guilty of too often in the past. The slow but sure accretion of complexity of inout is a textbook example of where that leads.I actually agree, someone with as little experience as I had should not have been listened to when making such a feature :) If I could do it over again, I would still want this feature, but obviously, we could make sane simple rules for it. They are actually quite easy to understand. -Steve
Apr 15 2016
On Friday, 15 April 2016 at 20:03:07 UTC, Andrei Alexandrescu wrote:We should really do away with the cowboy style of designing language, which sadly Walter and I have been guilty of too often in the past. The slow but sure accretion of complexity of inout is a textbook example of where that leads. AndreiThis deserves to be a poster with a golden frame. You've got lucky with pure (modulo corner cases) and ctfe, much less lucky with safe, trusted, system, inout, shared, scope, property.
Apr 17 2016
On Sunday, 17 April 2016 at 14:30:59 UTC, QAston wrote:You've got lucky with pure (modulo corner cases) and ctfe, much less lucky with safe, trusted, system, inout, shared, scope, property.The safe troika is a good design (except safe should be the default), the implementation is lacking though. Ideallists want to make safe strict now, but break code sometimes even without basic workarounds for memory-safe code. Pragmatists want to avoid breakage but make the subset of safe code wider, making the definition more complex. There seems to be a stalemate. scope, if implemented for reference types, wouldn't scale well. It should be the default, with __escape meaning scope(false). I think it's an uphill battle arguing for this, but it is crucial to avoiding GC without runtime checks. At least for non-GC code in a general way. I think property is OK. I think the controversy at the time was about optional brackets in function calls, which is different.
Apr 17 2016
On Sunday, 17 April 2016 at 16:44:50 UTC, Nick Treleaven wrote:The safe troika is a good design (except safe should be the default), the implementation is lacking though. Ideallists want to make safe strict now, but break code sometimes even without basic workarounds for memory-safe code. Pragmatists want to avoid breakage but make the subset of safe code wider, making the definition more complex. There seems to be a stalemate.Yeah, but for example rust deals with the same problem with a single keyword.scope, if implemented for reference types, wouldn't scale well. It should be the default, with __escape meaning scope(false). I think it's an uphill battle arguing for this, but it is crucial to avoiding GC without runtime checks. At least for non-GC code in a general way.scope (for function parameters) cannot be implemented in backwards compatible way because a lot of code uses in (which is const^scope)I think property is OK. I think the controversy at the time was about optional brackets in function calls, which is different.First property + compiler switch, now property + deprecated switch. When should I use property? For all the getters? Should I start with property or with member access? Does it even matter because of optional parens? Why do I even need to care about this? Sure all of the things I've mentioned can be defended. The question is not whether they have a usecase (because all of them do), but whether return on investment for them is good enough and how they interact with the rest of the language. CTFE does what you'd expect it to do - constant folding is intuitive and requires little to no code changes. Purity is orthogonal to the rest of the language (modulo corner cases) and enables some patterns for immutable value creation. Those (and others - the stuff that's good doesn't come to mind because it works) have higher ROI and aren't as much of a burden for library writers.
Apr 17 2016
On 17.04.2016 19:39, QAston wrote:First property + compiler switch, now property + deprecated switch. When should I use property? For all the getters? Should I start with property or with member access? Does it even matter because of optional parens? Why do I even need to care about this?property is in a bad state right now. The behavior that used to be enabled by -property has been decided against, and now property has only one effect that I can think of off the top of my head, and it's rather subtle: ---- int foo() {return 0;} property int bar() {return 0;} pragma(msg, typeof(foo)); /* int() */ pragma(msg, typeof(bar)); /* int */ pragma(msg, typeof(&foo)); /* int function() ref */ pragma(msg, typeof(&bar)); /* int function() property ref */ ---- I don't think anyone is really happy with the current property, but everyone is probably tired of discussing it.
Apr 17 2016
On Sunday, 17 April 2016 at 17:39:48 UTC, QAston wrote:First property + compiler switch, now property + deprecated switch. When should I use property? For all the getters? Should I start with property or with member access? Does it even matter because of optional parens? Why do I even need to care about this?Rationale behind DIP23 seems to make language usable without property and provide a puristic feature for those who are into it and for one corner case.
Apr 19 2016
On 17.04.2016 18:44, Nick Treleaven wrote:I think property is OK.No, it isn't: import std.stdio; struct S{ property int delegate() foo(){ return ()=>3; } } void main(){ S s; writeln(s.foo()); // "int delegate()" }
Apr 17 2016
On Sunday, 17 April 2016 at 21:20:49 UTC, Timon Gehr wrote:On 17.04.2016 18:44, Nick Treleaven wrote:Seriously, property is one of the biggest SNAFUs of the language. I think I'll write an editorial about this stuff in TWID tonight. (I'm also very skeptical of the value of pure, safe, nothrow, and nogc)I think property is OK.No, it isn't:
Apr 17 2016
On Sunday, 17 April 2016 at 23:03:26 UTC, Adam D. Ruppe wrote:On Sunday, 17 April 2016 at 21:20:49 UTC, Timon Gehr wrote:nothrow may be useful for passing callbacks in C functions. shared currently is useless too tbwOn 17.04.2016 18:44, Nick Treleaven wrote:Seriously, property is one of the biggest SNAFUs of the language. I think I'll write an editorial about this stuff in TWID tonight. (I'm also very skeptical of the value of pure, safe, nothrow, and nogc)I think property is OK.No, it isn't:
Apr 17 2016
On Monday, 18 April 2016 at 00:53:26 UTC, Temtaime wrote:shared currently is useless too tbwshared did catch bugs in phobos and user code, that would otherwise sneak in.
Apr 19 2016
On Sunday, 17 April 2016 at 23:03:26 UTC, Adam D. Ruppe wrote:On Sunday, 17 April 2016 at 21:20:49 UTC, Timon Gehr wrote:Today I learned a new acronym. Fit property perfectly.On 17.04.2016 18:44, Nick Treleaven wrote:Seriously, property is one of the biggest SNAFUs of the language.I think property is OK.No, it isn't:
Apr 17 2016
On Sunday, 17 April 2016 at 23:03:26 UTC, Adam D. Ruppe wrote:On Sunday, 17 April 2016 at 21:20:49 UTC, Timon Gehr wrote:As a big user of nogc, I'd disagree. nogc is a bit hard to use and effectively split the language in two, but gives the absolute confidence that nothing will block. In audio callbacks and you are supposed to use tryLock and atomics instead of locking, so allocating is a big problem. And it's very easy to let something passthrough like a rogue closure or an array literal. nogc is a big safety net I thought wasn't needed, until I had to make nogc code. Personnally I wish synchronized, comma operator, and actively harmful things would go. nothrow provides little value, but no negative value.On 17.04.2016 18:44, Nick Treleaven wrote:Seriously, property is one of the biggest SNAFUs of the language. I think I'll write an editorial about this stuff in TWID tonight. (I'm also very skeptical of the value of pure, safe, nothrow, and nogc)I think property is OK.No, it isn't:
Apr 18 2016
On Monday, 18 April 2016 at 08:52:19 UTC, Guillaume Piolat wrote:Personnally I wish synchronized, comma operator, and actively harmful things would go. nothrow provides little value, but no negative value.And shared and property :) But I guess this isn't Christmas already.
Apr 18 2016
On Monday, 18 April 2016 at 08:53:31 UTC, Guillaume Piolat wrote:And shared and property :)I still want to see property fixed rather than removed - the edge case with returning a delegate is an interesting one to me (though that's ALL I want it to do, leave everything else alone)
Apr 18 2016
(It seems my reply got lost somewhere, reposting...) On Friday, 15 April 2016 at 19:28:02 UTC, Andrei Alexandrescu wrote:A better support for this argument is std.array.replaceSlice at https://github.com/D-Programming-Language/phobos/blob/master/std/array.d#L2594: inout(T)[] replaceSlice(T)(inout(T)[] s, in T[] slice, in T[] replacement); So here we are guaranteed that (a) the result type is the same as the first argument, and (b) the first argument is never modified even if a mutable slice is passed.What are the plans for DIP25's `return` attribute? Because with it, the compiler has enough information to know that the return value aliases `s`: const(T)[] replaceSlice(T)(const(T)[] s return, in T[] slice, in T[] replacement); If the function is passed a mutable `s`, its return value can be implicitly convertible to `T[]`.
Apr 16 2016
On 16/04/2016 12:40, Marc Schütz wrote:What are the plans for DIP25's `return` attribute? Because with it, the compiler has enough information to know that the return value aliases `s`: const(T)[] replaceSlice(T)(const(T)[] s return, in T[] slice, in T[] replacement); If the function is passed a mutable `s`, its return value can be implicitly convertible to `T[]`.AIUI, functions don't have to return part of the parameter tagged with return, it can return anything. See: http://wiki.dlang.org/DIP25#Types_of_Result_vs._Parameters
Apr 16 2016
On Saturday, 16 April 2016 at 11:49:21 UTC, Nick Treleaven wrote:On 16/04/2016 12:40, Marc Schütz wrote:I'm not sure. That section says that the situation may change in the future. Other parts of the DIP can be read both ways, but it doesn't mention aliasing explicitly. As this is currently still experimental and not a complete design anyway, we can change it to fit our needs.What are the plans for DIP25's `return` attribute? Because with it, the compiler has enough information to know that the return value aliases `s`: const(T)[] replaceSlice(T)(const(T)[] s return, in T[] slice, in T[] replacement); If the function is passed a mutable `s`, its return value can be implicitly convertible to `T[]`.AIUI, functions don't have to return part of the parameter tagged with return, it can return anything. See: http://wiki.dlang.org/DIP25#Types_of_Result_vs._Parameters
Apr 18 2016
On 15-Apr-2016 08:38, Andrei Alexandrescu wrote:On 04/15/2016 12:23 AM, Jonathan M Davis via Digitalmars-d wrote:[snip]On Thursday, April 14, 2016 23:10:12 Andrei Alexandrescu via Digitalmars-d wrote:Love this trend! inout is a monstrously complicated feature solving minor inconvenience. -- Dmitry Olshansky- Jonathan M DavisI think we should deprecate inout. For real. It costs way too much for what it does. For all I can tell most of D's proponents don't know how it works. -- Andrei
Apr 15 2016
On 2016-04-15 07:38, Andrei Alexandrescu wrote:I think we should deprecate inout. For real. It costs way too much for what it does. For all I can tell most of D's proponents don't know how it works. -- AndreiIf "inout" is only used as a way avoid code duplication, both when writing the code and the compiler generating the code. Then that can be solved with two steps: 1. Improve the compiler to remove duplicated functions overloaded on constness. That is, they generate the exact same code and and the only difference is the constness of the functions. This is a useful improvement regardless 2. Write a string mixin that duplicates a function three times, one for each type of constness: // Assuming "inout" is removed from the language and not a keyword anymore mixin(inout(q{ inout(T)[] replaceSlice(T)(inout(T)[] s, in T[] slice, in T[] replacement) { ... } }); The "input" function would need to parse arbitrary D code and create three version of the passed in function declaration, mutable, const and immutable. In theory libdparse could be used for this but it doesn't work at compile time. The downside is that it looks really ugly when defining an inout function. But, with AST macros it could look like this: inout inout(T)[] replaceSlice(T)(inout(T)[] s, in T[] slice, in T[] replacement); -- /Jacob Carlborg
Apr 16 2016
On Friday, 15 April 2016 at 04:23:29 UTC, Jonathan M Davis wrote:IIRC, the problem has to do with ranges of inout elements working correctly, which gets really funky, because inout is a temporary thing and not a full-on type constructor/qualifier. I believe that Kenji is the one that implemented the fix, and I think that he explained it in the newsgroup at some point. Certainly, there have been a few times that it's come up in D.Learn when folks ask what the heck it is, so there should be a few posts floating around with an explanation. This is the only useful post that I could find in a quick search though:Whatever the problem is, none of this seems like a good solution.
Apr 15 2016
On 04/15/2016 03:42 AM, deadalnix wrote:On Friday, 15 April 2016 at 04:23:29 UTC, Jonathan M Davis wrote:I agree. -- AndreiIIRC, the problem has to do with ranges of inout elements working correctly, which gets really funky, because inout is a temporary thing and not a full-on type constructor/qualifier. I believe that Kenji is the one that implemented the fix, and I think that he explained it in the newsgroup at some point. Certainly, there have been a few times that it's come up in D.Learn when folks ask what the heck it is, so there should be a few posts floating around with an explanation. This is the only useful post that I could find in a quick search though:Whatever the problem is, none of this seems like a good solution.
Apr 15 2016
On Friday, 15 April 2016 at 04:23:29 UTC, Jonathan M Davis wrote:Certainly, there have been a few times that it's come up in D.Learn when folks ask what the heck it is, so there should be a few posts floating around with an explanation. This is the only useful post that I could find in a quick search though: http://forum.dlang.org/post/mh68p8$2p56$1 digitalmars.comHe says:Alternatively, you could have the lambda take an R as a parameter. Or fix the semantics ...Assuming it works OK, that seems much cleaner: (R r) { if (r.empty) {} ... }
Apr 15 2016
On 4/15/16 8:59 AM, Nick Treleaven wrote:On Friday, 15 April 2016 at 04:23:29 UTC, Jonathan M Davis wrote:That makes other unittests fail (those with noncopyable ranges). Overall we really need to spend some time on making Phobos simpler and better. The mishmash of styles and variable quality of contributions has slowly been gnawing at the sheer quality of the code. AndreiCertainly, there have been a few times that it's come up in D.Learn when folks ask what the heck it is, so there should be a few posts floating around with an explanation. This is the only useful post that I could find in a quick search though: http://forum.dlang.org/post/mh68p8$2p56$1 digitalmars.comHe says:Alternatively, you could have the lambda take an R as a parameter. Or fix the semantics ...Assuming it works OK, that seems much cleaner: (R r) { if (r.empty) {} ... }
Apr 15 2016
On Friday, 15 April 2016 at 03:10:12 UTC, Andrei Alexandrescu wrote:Consider: https://github.com/D-Programming-Language/phobos/blob/master/std/range/primitives.d#L152 There is no explanation to it in the source code, and the line blames to https://github.com/D-Programming-Language/phobos/pull/2661 (irrelevant). Commenting it out yields a number of unittest compilation errors, neither informative about the root of the problem and indicative as to how the parameter solves it. There are two issues here: 1. Once a problem/solution pair of this degree of subtlety crops up, we need to convince ourselves that that's sensible. If we deem it not so, we look into improving the language to make the problem disappear. 2. There needs to be documentation for people working on the standard library so they don't need to waste time on their own discovery process. We want Phobos to be beautiful, a prime example of good D code. Admittedly, it also needs to be very general and efficient, which sometimes gets in the way. But we cannot afford an accumulation of mad tricks to obscure the large design. Andrei`(int inout = 0)` is not the only problem with that template -- and it's bothered me for years. `is(typeof( () { ... } ) )` as a whole looks like a "trick" to me. It's not going to be immediately obvious to someone who reads the D spec, and then that code, what that template does. I think that behavioral type checks are common enough in D that it should have it's own first-class syntax. -Shammah
Apr 14 2016
On 04/15/2016 02:40 AM, Shammah Chancellor wrote:I think that behavioral type checks are common enough in D that it should have it's own first-class syntax.No. -- Andrei
Apr 15 2016
On 4/14/2016 8:10 PM, Andrei Alexandrescu wrote:Commenting it out yields a number of unittest compilation errors, neither informative about the root of the problem and indicative as to how the parameter solves it.https://issues.dlang.org/show_bug.cgi?id=15926
Apr 14 2016
I think it has something to do with making the function, in this case a lambda, inout, so that it can accept inout types. Then the typeof bit is a weird way to writing something like __traits(compiles, ...) , because functions which have no type result in void, and that fails the typeof check. If we do end up replacing inout with something else, I would like something which solves the problem of declaring functions returning ranges of either mutable, const, or immutable. I've struggled with that before: https://github.com/w0rp/dstruct/blob/master/source/dstruct/graph.d#L628
Apr 15 2016
On Friday, 15 April 2016 at 07:33:42 UTC, w0rp wrote:I think it has something to do with making the function, in this case a lambda, inout, so that it can accept inout types. Then the typeof bit is a weird way to writing something like __traits(compiles, ...) , because functions which have no type result in void, and that fails the typeof check. If we do end up replacing inout with something else, I would like something which solves the problem of declaring functions returning ranges of either mutable, const, or immutable. I've struggled with that before: https://github.com/w0rp/dstruct/blob/master/source/dstruct/graph.d#L628To clarify my example. My problem was that I had a container which was immutable, and I wanted a range over the immutable elements, where the range itself is of course mutable. Getting that to work was a tad tricky. You can't take an inout() container and return an inout() range, because then an immutable container will produce an immutable range, which isn't useful. I don't think you can return a mutable range containing inout() elements either.
Apr 15 2016
On 04/15/2016 02:49 AM, Walter Bright wrote:On 4/14/2016 8:10 PM, Andrei Alexandrescu wrote:Nice, thanks. I think I can put a finger on what bothers me the most: adding that "inout int = 0" to make code work cannot be an acceptable solution to any problem. So the fact that the problem exists is the actual problem. It's basic sense and sensibility in engineering. -- AndreiCommenting it out yields a number of unittest compilation errors, neither informative about the root of the problem and indicative as to how the parameter solves it.https://issues.dlang.org/show_bug.cgi?id=15926
Apr 15 2016
On 15.04.2016 05:10, Andrei Alexandrescu wrote:Consider: https://github.com/D-Programming-Language/phobos/blob/master/std/range/primitives.d#L152 ...Related: Phobos should never use is(typeof(...)). Contrary to popular belief, is(typeof(...)) is not the same as __traits(compiles,...). void main(){ int x; static void foo(){ static assert(is(typeof({return x;}))); static assert(!__traits(compiles,{return x;})); } } typeof suspends context access checks. This is almost never what you want when checking for compilability.There is no explanation to it in the source code, and the line blames to https://github.com/D-Programming-Language/phobos/pull/2661 (irrelevant). Commenting it out yields a number of unittest compilation errors, neither informative about the root of the problem and indicative as to how the parameter solves it. There are two issues here: 1. Once a problem/solution pair of this degree of subtlety crops up, we need to convince ourselves that that's sensible. If we deem it not so, we look into improving the language to make the problem disappear. ...Declaring variables with inout in their type is only allowed for stack variables in functions that have inout parameters. The (inout int) trick attempts to allow such types to be ranges. It is not even a correct fix: Most of Phobos code assumes that ranges be struct fields. The following code causes a compilation failure in the guts of std.algorithm: inout(int)[] foo(inout(int)[] x){ static assert(isInputRange!(typeof(x))); return x.map!(x=>x).array; } What good is an "InputRange" that does not support map? The fundamental problem is that inout is disallows certain kinds of composition. It's a flawed language primitive. The way to fix this is to have parametric polymorphism in the language.
Apr 15 2016
On 15.04.2016 11:07, Timon Gehr wrote:... Most of Phobos code assumes that ranges be struct fields.Most of Phobos assumes that ranges can beThe fundamental problem is that inout is disallows certain kinds of composition. ...inout disallows
Apr 15 2016
On Friday, 15 April 2016 at 09:07:27 UTC, Timon Gehr wrote:Related: Phobos should never use is(typeof(...)). Contrary to popular belief, is(typeof(...)) is not the same as __traits(compiles,...).I don't think it should be using __traits(compiles) either. I'd prefer to see built from the other reflection primitives... though I'll grant that compiles is flexible. hasMember!(Range, "empty") isn't as specific as the current test... and is(typeof(Range.init.empty) : bool) isn't as flexible (I don't think that takes an empty that returns an opCast:bool item) But regardless, I still kinda prefer the idea of building these reflection helper functions so they do cover the cases nicely... then a helper function that takes a list of conditions and tells you which one failed... hmm, this is getting interesting.
Apr 15 2016
On 04/15/2016 05:07 AM, Timon Gehr wrote:The fundamental problem is that inout is disallows certain kinds of composition. It's a flawed language primitive.I agree. The more I try things with it the more awfully complex and useless it is. inout must go. -- Andrei
Apr 15 2016
Am Fri, 15 Apr 2016 09:44:05 -0400 schrieb Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>: inout must go. -- Andrei Ceterum censeo Carthaginem esse delendam. -- Marcus Porcius Cato :o) -- Marco
Apr 16 2016
On Saturday, 16 April 2016 at 22:06:10 UTC, Marco Leise wrote:Am Fri, 15 Apr 2016 09:44:05 -0400 schrieb Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>: inout must go. -- Andrei Ceterum censeo Carthaginem esse delendam. -- Marcus Porcius Cato :o)What does that have to do with what he said? Are you comparing him to Cato?
Apr 16 2016
On Friday, 15 April 2016 at 03:10:12 UTC, Andrei Alexandrescu wrote:We want Phobos to be beautiful, a prime example of good D code. Admittedly, it also needs to be very general and efficient, which sometimes gets in the way. But we cannot afford an accumulation of mad tricks to obscure the large design. AndreiWhy didn't we go with all functions being able to infer const, pure etc rather than just templates?
Apr 15 2016
On Friday, 15 April 2016 at 12:54:11 UTC, ixid wrote:Why didn't we go with all functions being able to infer const, pure etc rather than just templates?Non-templated function may not have their source code available. For consistency, non-template function have no inference.
Apr 15 2016
On Friday, 15 April 2016 at 12:54:11 UTC, ixid wrote:On Friday, 15 April 2016 at 03:10:12 UTC, Andrei Alexandrescu wrote:The problem is essentially untractable when there are loops in the call graph. That being said, it would make sense to do it for auto functions.We want Phobos to be beautiful, a prime example of good D code. Admittedly, it also needs to be very general and efficient, which sometimes gets in the way. But we cannot afford an accumulation of mad tricks to obscure the large design. AndreiWhy didn't we go with all functions being able to infer const, pure etc rather than just templates?
Apr 15 2016
On Friday, 15 April 2016 at 03:10:12 UTC, Andrei Alexandrescu wrote:Consider: https://github.com/D-Programming-Language/phobos/blob/master/std/range/primitives.d#L152 There is no explanation to it in the source code, and the line blames to https://github.com/D-Programming-Language/phobos/pull/2661 (irrelevant).I've been wondering what that is myself, so I've just cargo-cult-copied it into my code. Thanks for the post.
Apr 15 2016
On 4/14/16 11:10 PM, Andrei Alexandrescu wrote:Consider: https://github.com/D-Programming-Language/phobos/blob/master/std/range/primitives.d#L152It works around a limitation of inout that isn't necessary (even though I thought it was being helpful when I suggested it). That is, functions without inout parameters cannot declare local inout variables. But this isn't really necessary, and should be fixed. I will discuss this in my talk in a few weeks. Note, the =0 part isn't necessary right now, since it's not called. It's just used to test if the function can compile. In short, my opinion on inout is that it has some unnecessary limitations, which can be removed, and inout will work as mostly expected. These requirements to work around the limitations will go away. I expect after reading this thread that the Q&A will be.. interesting. -Steve
Apr 15 2016
On 15.04.2016 17:22, Steven Schveighoffer wrote:On 4/14/16 11:10 PM, Andrei Alexandrescu wrote:That's potentially dangerous. What about cases like the following? void main(){ inout(int)[] x=[1,2,3]; immutable(int) a; int b; inout(int)[] foo(inout int){ return x; } immutable(int)[] y=foo(a); int[] z=foo(b); }Consider: https://github.com/D-Programming-Language/phobos/blob/master/std/range/primitives.d#L152It works around a limitation of inout that isn't necessary (even though I thought it was being helpful when I suggested it). That is, functions without inout parameters cannot declare local inout variables. But this isn't really necessary, and should be fixed. I will discuss this in my talk in a few weeks. ...Note, the =0 part isn't necessary right now, since it's not called. It's just used to test if the function can compile. In short, my opinion on inout is that it has some unnecessary limitations, which can be removed, and inout will work as mostly expected. These requirements to work around the limitations will go away. ...Other important limitations of inout are e.g.: - inout variables cannot be fields. - There can be only one inout in scope.I expect after reading this thread that the Q&A will be.. interesting. -Steve
Apr 15 2016
On 4/15/16 3:48 PM, Timon Gehr wrote:On 15.04.2016 17:22, Steven Schveighoffer wrote:We don't need to guess: void foo (inout int) { inout(int)[] x=[1,2,3]; immutable(int) a; int b; inout(int)[] foo(inout int){ return x; } immutable(int)[] y=foo(a); // line 9 int[] z=foo(b); // line 10 } testinout.d(9): Error: modify inout to immutable is not allowed inside inout function testinout.d(10): Error: modify inout to mutable is not allowed inside inout functionOn 4/14/16 11:10 PM, Andrei Alexandrescu wrote:That's potentially dangerous. What about cases like the following? void main(){ inout(int)[] x=[1,2,3]; immutable(int) a; int b; inout(int)[] foo(inout int){ return x; } immutable(int)[] y=foo(a); int[] z=foo(b); }Consider: https://github.com/D-Programming-Language/phobos/blob/master/std/range/primitives.d#L152It works around a limitation of inout that isn't necessary (even though I thought it was being helpful when I suggested it). That is, functions without inout parameters cannot declare local inout variables. But this isn't really necessary, and should be fixed. I will discuss this in my talk in a few weeks. ...I have a way to make this work. This is actually the most major sticking point in inout. The only correct thing is to keep is that globals/static variables cannot be typed inout.Note, the =0 part isn't necessary right now, since it's not called. It's just used to test if the function can compile. In short, my opinion on inout is that it has some unnecessary limitations, which can be removed, and inout will work as mostly expected. These requirements to work around the limitations will go away. ...Other important limitations of inout are e.g.: - inout variables cannot be fields.- There can be only one inout in scope.This is not so much a problem I think. -Steve
Apr 15 2016
On 04/15/2016 04:03 PM, Steven Schveighoffer wrote:I have a way to make this work. This is actually the most major sticking point in inout. The only correct thing is to keep is that globals/static variables cannot be typed inout.Another special case? The only correct thing is to simplify the language to everybody's benefit. -- Andrei
Apr 15 2016
On 4/15/16 4:08 PM, Andrei Alexandrescu wrote:On 04/15/2016 04:03 PM, Steven Schveighoffer wrote:This is not a special case any more than disallowing access of shared data from a pure function is a special case. In fact, you could allow inout variables as static or globals, but just couldn't copy them to local inout variables (except full value types). The point is that between 2 different calls to inout, the wrapper means something different. A global/static persists between calls. -SteveI have a way to make this work. This is actually the most major sticking point in inout. The only correct thing is to keep is that globals/static variables cannot be typed inout.Another special case? The only correct thing is to simplify the language to everybody's benefit. -- Andrei
Apr 15 2016
On 15.04.2016 22:03, Steven Schveighoffer wrote:On 4/15/16 3:48 PM, Timon Gehr wrote:I'm very aware of that: https://issues.dlang.org/show_bug.cgi?id=10758 main is not an inout function in the example above. I.e. if we just change the compiler minimally such as to allow making inout local variables, the above example will violate immutability guarantees. You can also imagine cases where the inout local variable is defined only after the local inout function has been declared and called with a non-inout argument. At which point does the constraint become active? etc. We cannot _simply_ allow declaring inout locals.On 15.04.2016 17:22, Steven Schveighoffer wrote:We don't need to guess: void foo (inout int) { inout(int)[] x=[1,2,3]; immutable(int) a; int b; inout(int)[] foo(inout int){ return x; } immutable(int)[] y=foo(a); // line 9 int[] z=foo(b); // line 10 } testinout.d(9): Error: modify inout to immutable is not allowed inside inout function testinout.d(10): Error: modify inout to mutable is not allowed inside inout functionOn 4/14/16 11:10 PM, Andrei Alexandrescu wrote:That's potentially dangerous. What about cases like the following? void main(){ inout(int)[] x=[1,2,3]; immutable(int) a; int b; inout(int)[] foo(inout int){ return x; } immutable(int)[] y=foo(a); int[] z=foo(b); }Consider: https://github.com/D-Programming-Language/phobos/blob/master/std/range/primitives.d#L152It works around a limitation of inout that isn't necessary (even though I thought it was being helpful when I suggested it). That is, functions without inout parameters cannot declare local inout variables. But this isn't really necessary, and should be fixed. I will discuss this in my talk in a few weeks. ...Without syntax changes? Can the struct/class instances with inout fields be returned from the enclosing inout function?I have a way to make this work.Note, the =0 part isn't necessary right now, since it's not called. It's just used to test if the function can compile. In short, my opinion on inout is that it has some unnecessary limitations, which can be removed, and inout will work as mostly expected. These requirements to work around the limitations will go away. ...Other important limitations of inout are e.g.: - inout variables cannot be fields.This is actually the most major sticking point in inout. The only correct thing is to keep is that globals/static variables cannot be typed inout.I think it is. It's just not the prevalent limitation one runs in at the moment. It will be more of a problem once functions can return structs with inout fields. IMHO compositionality should be ensured for a language feature from the start.- There can be only one inout in scope.This is not so much a problem I think. ...
Apr 15 2016
On 4/15/16 4:27 PM, Timon Gehr wrote:On 15.04.2016 22:03, Steven Schveighoffer wrote:There's no difference between a function that declares its variables inout within its parameters or one that declares them locally. They should be treated the same once the function starts compiling.On 4/15/16 3:48 PM, Timon Gehr wrote:I'm very aware of that: https://issues.dlang.org/show_bug.cgi?id=10758 main is not an inout function in the example above. I.e. if we just change the compiler minimally such as to allow making inout local variables, the above example will violate immutability guarantees. You can also imagine cases where the inout local variable is defined only after the local inout function has been declared and called with a non-inout argument. At which point does the constraint become active? etc. We cannot _simply_ allow declaring inout locals.On 15.04.2016 17:22, Steven Schveighoffer wrote:We don't need to guess: void foo (inout int) { inout(int)[] x=[1,2,3]; immutable(int) a; int b; inout(int)[] foo(inout int){ return x; } immutable(int)[] y=foo(a); // line 9 int[] z=foo(b); // line 10 } testinout.d(9): Error: modify inout to immutable is not allowed inside inout function testinout.d(10): Error: modify inout to mutable is not allowed inside inout functionOn 4/14/16 11:10 PM, Andrei Alexandrescu wrote:That's potentially dangerous. What about cases like the following? void main(){ inout(int)[] x=[1,2,3]; immutable(int) a; int b; inout(int)[] foo(inout int){ return x; } immutable(int)[] y=foo(a); int[] z=foo(b); }Consider: https://github.com/D-Programming-Language/phobos/blob/master/std/range/primitives.d#L152It works around a limitation of inout that isn't necessary (even though I thought it was being helpful when I suggested it). That is, functions without inout parameters cannot declare local inout variables. But this isn't really necessary, and should be fixed. I will discuss this in my talk in a few weeks. ...Yes, as long as inout is wrapping inout. We run into this currently with inout functions that create local types. e.g. emplace. Obviously inout cannot be unwrapped if it is typed on a field of a struct or class. So the unwrapping has to result in inout.Without syntax changes? Can the struct/class instances with inout fields be returned from the enclosing inout function?I have a way to make this work.Note, the =0 part isn't necessary right now, since it's not called. It's just used to test if the function can compile. In short, my opinion on inout is that it has some unnecessary limitations, which can be removed, and inout will work as mostly expected. These requirements to work around the limitations will go away. ...Other important limitations of inout are e.g.: - inout variables cannot be fields.At the point where we need to tag multiple pools of inout parameters, the complexity of the language doesn't justify the benefits. We could make it possible, for instance, to templatize the mutability modifier instead of using a specific keyword. Then you could have foo(int)[]. Then I think you could do all this (and scrap inout), but I wouldn't want to work in that language. -SteveI think it is. It's just not the prevalent limitation one runs in at the moment. It will be more of a problem once functions can return structs with inout fields. IMHO compositionality should be ensured for a language feature from the start.- There can be only one inout in scope.This is not so much a problem I think. ...
Apr 15 2016
On 04/15/2016 04:47 PM, Steven Schveighoffer wrote:There's no difference between a function that declares its variables inout within its parameters or one that declares them locally.So now we get to things like: void fun() { inout int ohHello = 42; ... } How to explain such a construct? Not to mention globals of that type are not allowed. Andrei
Apr 15 2016
On 15.04.2016 23:03, Andrei Alexandrescu wrote:On 04/15/2016 04:47 PM, Steven Schveighoffer wrote:It's an int that has not decided yet whether it wants to be mutable, const or immutable and goes out of scope before it is able to make up its mind.There's no difference between a function that declares its variables inout within its parameters or one that declares them locally.So now we get to things like: void fun() { inout int ohHello = 42; ... } How to explain such a construct? Not to mention globals of that type are not allowed. Andrei
Apr 15 2016
On 15.04.2016 22:47, Steven Schveighoffer wrote:On 4/15/16 4:27 PM, Timon Gehr wrote:Yes, there is. Semantic analysis sees the parameter types before it sees the body.On 15.04.2016 22:03, Steven Schveighoffer wrote:There's no difference between a function that declares its variables inout within its parameters or one that declares them locally. ...On 4/15/16 3:48 PM, Timon Gehr wrote:I'm very aware of that: https://issues.dlang.org/show_bug.cgi?id=10758 main is not an inout function in the example above. I.e. if we just change the compiler minimally such as to allow making inout local variables, the above example will violate immutability guarantees. You can also imagine cases where the inout local variable is defined only after the local inout function has been declared and called with a non-inout argument. At which point does the constraint become active? etc. We cannot _simply_ allow declaring inout locals.On 15.04.2016 17:22, Steven Schveighoffer wrote:We don't need to guess: void foo (inout int) { inout(int)[] x=[1,2,3]; immutable(int) a; int b; inout(int)[] foo(inout int){ return x; } immutable(int)[] y=foo(a); // line 9 int[] z=foo(b); // line 10 } testinout.d(9): Error: modify inout to immutable is not allowed inside inout function testinout.d(10): Error: modify inout to mutable is not allowed inside inout functionOn 4/14/16 11:10 PM, Andrei Alexandrescu wrote:That's potentially dangerous. What about cases like the following? void main(){ inout(int)[] x=[1,2,3]; immutable(int) a; int b; inout(int)[] foo(inout int){ return x; } immutable(int)[] y=foo(a); int[] z=foo(b); }Consider: https://github.com/D-Programming-Language/phobos/blob/master/std/range/primitives.d#L152It works around a limitation of inout that isn't necessary (even though I thought it was being helpful when I suggested it). That is, functions without inout parameters cannot declare local inout variables. But this isn't really necessary, and should be fixed. I will discuss this in my talk in a few weeks. ...They should be treated the same once the function starts compiling. ...I think I have stated clearly why this is impossible. :POk.Yes, as long as inout is wrapping inout. We run into this currently with inout functions that create local types. e.g. emplace. Obviously inout cannot be unwrapped if it is typed on a field of a struct or class. So the unwrapping has to result in inout. ...Without syntax changes? Can the struct/class instances with inout fields be returned from the enclosing inout function?I have a way to make this work.Note, the =0 part isn't necessary right now, since it's not called. It's just used to test if the function can compile. In short, my opinion on inout is that it has some unnecessary limitations, which can be removed, and inout will work as mostly expected. These requirements to work around the limitations will go away. ...Other important limitations of inout are e.g.: - inout variables cannot be fields.I think this is a funny place to draw the line, but I guess this is a matter of taste.At the point where we need to tag multiple pools of inout parameters, the complexity of the language doesn't justify the benefits. ...I think it is. It's just not the prevalent limitation one runs in at the moment. It will be more of a problem once functions can return structs with inout fields. IMHO compositionality should be ensured for a language feature from the start.- There can be only one inout in scope.This is not so much a problem I think. ...We could make it possible, for instance, to templatize the mutability modifier instead of using a specific keyword. Then you could have foo(int)[]. Then I think you could do all this (and scrap inout), but I wouldn't want to work in that language. -SteveWell, that is precisely the way that languages with real type systems address issues like this one. D has many others like it. Note that for type systems, complexity and expressiveness do not necessarily correlate.
Apr 15 2016
On 04/15/2016 05:17 PM, Timon Gehr wrote:Well, that is precisely the way that languages with real type systems address issues like this one. D has many others like it. Note that for type systems, complexity and expressiveness do not necessarily correlate.Nicely put on both counts. (Well "real" is semantically sarcastic a bit.) I don't even disagree :o). -- Andrei
Apr 15 2016
On 4/15/16 5:17 PM, Timon Gehr wrote:On 15.04.2016 22:47, Steven Schveighoffer wrote:I don't know what the current implementation sees the function as doing. The way I look at it, the function context is like an extra parameter to the inner function. If it contains inout data, then that needs to be taken into account if the inner function has additional inout parameters. For example: inout(int) *x; inout(int) *foo(inout int) {return x;} foo is really taking 2 parameters: y and the context pointer that contains x. It almost looks like this: inout(int) *foo(inout int, ref inout(int) *x) { return x;} call this with: foo(1, x) And it won't compile. However, call it with: foo(inout(int)(1), x); and it should be fine, returning an inout(int)*.There's no difference between a function that declares its variables inout within its parameters or one that declares them locally. ...Yes, there is. Semantic analysis sees the parameter types before it sees the body.Impossible or difficult to do with the current implementation?They should be treated the same once the function starts compiling. ...I think I have stated clearly why this is impossible. :PI may have said this incorrectly. The language itself wouldn't really be that much more complex. It's the cost of understanding what each of the different inout pools mean. The benefit would be quite small, whereas there are obvious places inout makes sense -- the 'this' parameter and the return value. Then there is the syntax that would be required, I'm not sure what that looks like.At the point where we need to tag multiple pools of inout parameters, the complexity of the language doesn't justify the benefits. ...I think this is a funny place to draw the line, but I guess this is a matter of taste.Aye, solutions like Rebindable, which is pretty much a failure IMO, show how lack of expressiveness in the core language can't be easily substituted.We could make it possible, for instance, to templatize the mutability modifier instead of using a specific keyword. Then you could have foo(int)[]. Then I think you could do all this (and scrap inout), but I wouldn't want to work in that language.Well, that is precisely the way that languages with real type systems address issues like this one. D has many others like it.Note that for type systems, complexity and expressiveness do not necessarily correlate.Humans are creatures of habit and familiarity. To allow each library to define what words mean what for modifiers would be really difficult to deal with. -Steve
Apr 15 2016
On 15.04.2016 23:56, Steven Schveighoffer wrote:On 4/15/16 5:17 PM, Timon Gehr wrote:Rather, when the inout data is actually accessed.On 15.04.2016 22:47, Steven Schveighoffer wrote:I don't know what the current implementation sees the function as doing. The way I look at it, the function context is like an extra parameter to the inner function. If it contains inout data,There's no difference between a function that declares its variables inout within its parameters or one that declares them locally. ...Yes, there is. Semantic analysis sees the parameter types before it sees the body.then that needs to be taken into account if the inner function has additional inout parameters. ...That's sensible, of course. The current implementation is a lot more conservative though.For example: inout(int) *x; inout(int) *foo(inout int) {return x;} foo is really taking 2 parameters: y and the context pointer that contains x. It almost looks like this: inout(int) *foo(inout int, ref inout(int) *x) { return x;} call this with: foo(1, x) And it won't compile. However, call it with: foo(inout(int)(1), x); and it should be fine, returning an inout(int)*.What I'm saying is that the check that is currently implemented is not adequate for the new case. This is not terribly important though. The point was that there needs to be a design effort beyond lifting the limitation, and you seemed to claim that the current implementation already takes care of the presented issue, which is not the case. Your ideas are sound though.Impossible or difficult to do with the current implementation? ...They should be treated the same once the function starts compiling. ...I think I have stated clearly why this is impossible. :PThey would just be named parameters to the function on the type system level, similar to template arguments but not causing repeated instantiation.I may have said this incorrectly. The language itself wouldn't really be that much more complex. It's the cost of understanding what each of the different inout pools mean.At the point where we need to tag multiple pools of inout parameters, the complexity of the language doesn't justify the benefits. ...I think this is a funny place to draw the line, but I guess this is a matter of taste.The benefit would be quite small, whereas there are obvious places inout makes sense -- the 'this' parameter and the return value. ...The return value might contain more than one pointer, and functions often have more than one parameter.Then there is the syntax that would be required, I'm not sure what that looks like. ...Anything that is analogous to template parameters, e.g. an additional set of arguments with a different delimiter. Many workable possibilities. Anyway, it is unlikely to happen.I don't see how the library would do that.Aye, solutions like Rebindable, which is pretty much a failure IMO, show how lack of expressiveness in the core language can't be easily substituted.We could make it possible, for instance, to templatize the mutability modifier instead of using a specific keyword. Then you could have foo(int)[]. Then I think you could do all this (and scrap inout), but I wouldn't want to work in that language.Well, that is precisely the way that languages with real type systems address issues like this one. D has many others like it.Note that for type systems, complexity and expressiveness do not necessarily correlate.Humans are creatures of habit and familiarity. To allow each library to define what words mean what for modifiers would be really difficult to deal with. -Steve
Apr 15 2016
On 4/15/16 6:31 PM, Timon Gehr wrote:On 15.04.2016 23:56, Steven Schveighoffer wrote:I'm sorry, should have put on my standard disclaimer that I am not a compiler writer :) I actually have no idea how this is done in the compiler, just how a compiler should behave as I understand it in my head.Impossible or difficult to do with the current implementation? ...What I'm saying is that the check that is currently implemented is not adequate for the new case. This is not terribly important though. The point was that there needs to be a design effort beyond lifting the limitation, and you seemed to claim that the current implementation already takes care of the presented issue, which is not the case. Your ideas are sound though.Right, but again: these are named by the writer of the template, not the language, right? In that case, any identifier becomes a modifier. Or are you thinking of something different?I may have said this incorrectly. The language itself wouldn't really be that much more complex. It's the cost of understanding what each of the different inout pools mean.They would just be named parameters to the function on the type system level, similar to template arguments but not causing repeated instantiation.Of course, but the transference of mutability from parameter to return value is the obvious draw of such a wildcard. In most cases, there is only one return value, and therefore only one pool that needs to be handled. ref/out parameters can serve as alternate returns as well as composed types. It's not that functions don't have multiple returns with their own inout, but I don't think it's very common. As we get more and more obscure, the cost/benefit ratio for complexity vs. power gets higher. And already people don't like where we are right now with it.The benefit would be quite small, whereas there are obvious places inout makes sense -- the 'this' parameter and the return value. ...The return value might contain more than one pointer, and functions often have more than one parameter.Especially given the discussion happening here, I agree.Then there is the syntax that would be required, I'm not sure what that looks like. ...Anything that is analogous to template parameters, e.g. an additional set of arguments with a different delimiter. Many workable possibilities. Anyway, it is unlikely to happen.Just throwing a strawman out there: void foo(bingo = inout, zingo = inout)(bingo(int)* x, zingo(int)* y) So inside foo, bingo is one flavor of inout, zingo is another. This could vary library to library, function to function. It would work, and be sound design. I would just hate it is all :) Perhaps you have a better system in mind? -SteveHumans are creatures of habit and familiarity. To allow each library to define what words mean what for modifiers would be really difficult to deal with.I don't see how the library would do that.
Apr 15 2016
On Friday, 15 April 2016 at 23:05:14 UTC, Steven Schveighoffer wrote:On 4/15/16 6:31 PM, Timon Gehr wrote:inout(bool) newsgroup.revive_discussion(); can we make the compiler smart enough to solve the use-cases of inout (=auto const/immutable deducation)?[...]I'm sorry, should have put on my standard disclaimer that I am not a compiler writer :) I actually have no idea how this is done in the compiler, just how a compiler should behave as I understand it in my head. [...]
May 01 2016
On 5/1/16 7:58 PM, Seb wrote:On Friday, 15 April 2016 at 23:05:14 UTC, Steven Schveighoffer wrote:If we can find a way to replace inout with something that does effectively everything inout does, then I'm all for it. -SteveOn 4/15/16 6:31 PM, Timon Gehr wrote:inout(bool) newsgroup.revive_discussion(); can we make the compiler smart enough to solve the use-cases of inout (=auto const/immutable deducation)?[...]I'm sorry, should have put on my standard disclaimer that I am not a compiler writer :) I actually have no idea how this is done in the compiler, just how a compiler should behave as I understand it in my head. [...]
May 02 2016
On 15/04/2016 04:10, Andrei Alexandrescu wrote:Commenting it out yields a number of unittest compilation errors, neither informative about the root of the problem and indicative as to how the parameter solves it....2. There needs to be documentation for people working on the standard library so they don't need to waste time on their own discovery process.Perhaps use this, at least for now: // <Workaround explanation> alias InOutParam = inout int; ... (InOutParam) { ... } It's less cryptic at the use-site and people can lookup the definition to find an explanation.
Apr 16 2016