www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Error about constructor calls in loops/labels, but there are no loops

reply DarkHole <dark.hole1 yandex.ru> writes:
This strange code - https://run.dlang.io/is/BKgv49 - fails with 
error "Error: constructor calls not allowed in loops or after 
labels", but there is no loops or labels.
May 17 2018
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 5/17/18 3:55 PM, DarkHole wrote:
 This strange code - https://run.dlang.io/is/BKgv49 - fails with error 
 "Error: constructor calls not allowed in loops or after labels", but 
 there is no loops or labels.
Switch cases are labels. -Steve
May 17 2018
next sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 5/17/18 4:02 PM, Steven Schveighoffer wrote:
 On 5/17/18 3:55 PM, DarkHole wrote:
 This strange code - https://run.dlang.io/is/BKgv49 - fails with error 
 "Error: constructor calls not allowed in loops or after labels", but 
 there is no loops or labels.
Switch cases are labels.
That being said, I don't understand the point of this restriction in this case -- yes, it's after a label, but it's after the whole switch construct. It's probably a conservative application of a rule. You can fix by moving the final switch into a function: https://run.dlang.io/is/352nIC -Steve
May 17 2018
prev sibling parent reply DarkHole <dark.hole1 yandex.ru> writes:
On Thursday, 17 May 2018 at 20:02:19 UTC, Steven Schveighoffer 
wrote:
 On 5/17/18 3:55 PM, DarkHole wrote:
 This strange code - https://run.dlang.io/is/BKgv49 - fails 
 with error "Error: constructor calls not allowed in loops or 
 after labels", but there is no loops or labels.
Switch cases are labels. -Steve
But why?
May 17 2018
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 5/17/18 4:25 PM, DarkHole wrote:
 On Thursday, 17 May 2018 at 20:02:19 UTC, Steven Schveighoffer wrote:
 On 5/17/18 3:55 PM, DarkHole wrote:
 This strange code - https://run.dlang.io/is/BKgv49 - fails with error 
 "Error: constructor calls not allowed in loops or after labels", but 
 there is no loops or labels.
Switch cases are labels.
But why?
You mean why is it an error? Probably because the compiler needs to guarantee you are calling the super constructor, and it can't figure out the flow when it sees labels/loops. Not that it's always impossible, but it's likely a complication the compiler devs don't want to deal with. -Steve
May 17 2018
parent reply Yuxuan Shui <yshuiv7 gmail.com> writes:
On Thursday, 17 May 2018 at 20:32:23 UTC, Steven Schveighoffer 
wrote:
 On 5/17/18 4:25 PM, DarkHole wrote:
 On Thursday, 17 May 2018 at 20:02:19 UTC, Steven Schveighoffer 
 wrote:
 On 5/17/18 3:55 PM, DarkHole wrote:
 This strange code - https://run.dlang.io/is/BKgv49 - fails 
 with error "Error: constructor calls not allowed in loops or 
 after labels", but there is no loops or labels.
Switch cases are labels.
But why?
You mean why is it an error? Probably because the compiler needs to guarantee you are calling the super constructor, and it can't figure out the flow when it sees labels/loops. Not that it's always impossible, but it's likely a complication the compiler devs don't want to deal with. -Steve
Why isn't the compiler doing proper flow analysis? Is it that just no one bothered to implement it?
May 19 2018
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Saturday, May 19, 2018 22:54:16 Yuxuan Shui via Digitalmars-d wrote:
 On Thursday, 17 May 2018 at 20:32:23 UTC, Steven Schveighoffer

 wrote:
 On 5/17/18 4:25 PM, DarkHole wrote:
 On Thursday, 17 May 2018 at 20:02:19 UTC, Steven Schveighoffer

 wrote:
 On 5/17/18 3:55 PM, DarkHole wrote:
 This strange code - https://run.dlang.io/is/BKgv49 - fails
 with error "Error: constructor calls not allowed in loops or
 after labels", but there is no loops or labels.
Switch cases are labels.
But why?
You mean why is it an error? Probably because the compiler needs to guarantee you are calling the super constructor, and it can't figure out the flow when it sees labels/loops. Not that it's always impossible, but it's likely a complication the compiler devs don't want to deal with. -Steve
Why isn't the compiler doing proper flow analysis? Is it that just no one bothered to implement it?
As I understand it, in general, Walter is against doing much in the way of flow analysis, because it tends to become very difficult to get right in all cases and results in situations where the programmer is forced to do something in order to make the compiler shut up - e.g. in Java, you're forced to initialize all variables, and it's not uncommon that you have to initialize variables when you can clearly see that it shouldn't be necessary, but the compiler isn't smart enough to see that. Also, if D started use more flow analysis, then the exact rules of the flow analysis would have to be in the spec and set in stone, or you end up with code compiling on one compiler but not another. So, given issues like these Walter has taken the approach of trying to avoid doing much where flow analysis would be required by the spec. In the case of initialization, D's approach is to default-initialize evertything and then let the optimizer optimize out unnessary initializations where it can, which avoids the problem that Java has and eliminated the need to embed the flow analysis rules in the spec. And in general, the places that D does much in the way of flow analysis is in the optimization step where the compiler is free to change an improve how it does flow analysis. There are a few places wheree it's forced to do basic flow analysis (e.g. in constructors in cases like you ran into here), but in such cases, it pretty much always sticks to simple rules so that the flow analysis does not have to be complicated. - Jonathan M Davis
May 19 2018
next sibling parent reply KingJoffrey <KingJoffrey KingJoffrey.com> writes:
On Sunday, 20 May 2018 at 00:05:39 UTC, Jonathan M Davis wrote:
 As I understand it, in general, Walter is against doing ...
All I ever hear, is walter walter walter.... mmm..takes me back to my childhood.. https://www.youtube.com/watch?v=-yZHveWFvqM
May 19 2018
parent reply Neia Neutuladh <neia ikeran.org> writes:
On Sunday, 20 May 2018 at 02:53:10 UTC, KingJoffrey wrote:
 On Sunday, 20 May 2018 at 00:05:39 UTC, Jonathan M Davis wrote:
 As I understand it, in general, Walter is against doing ...
All I ever hear, is walter walter walter....
While it's mildly refreshing that you found something new to talk about, it would be nice if you found something productive to say. You're merely complaining that a person who has spent about two decades on D (for free), who has decades more experience with compilers, who is the main contributor to the D compiler, and who has a track record of being right a lot, is influential when it comes to changes to the language. This is social influence. Jonathan M Davis cited Walter's previous complaint because we generally care what Walter thinks, because we respect him. We won't always agree, but he usually has a decent reason for holding a position regarding compilers and programming languages. If this bothers you, make your own language. You might not want to design it yourself, lest you fall into the same trap. Maybe you can find a committee? Or use a random number generator to design it?
May 19 2018
parent KingJoffrey <KingJoffrey KingJoffrey.com> writes:
On Sunday, 20 May 2018 at 03:13:12 UTC, Neia Neutuladh wrote:
 While it's mildly refreshing that you found something new to 
 talk about, it would be nice if you found something productive 
 to say. You're merely complaining that a person who has spent 
 about two decades on D (for free), who has decades more 
 experience with compilers, who is the main contributor to the D 
 compiler, and who has a track record of being right a lot, is 
 influential when it comes to changes to the language.

 da da dah da dah dah dah dahhhhhhhh
Think of it this way.. that I'm injecting some quantum fluctuations into the D universe, in the hope that it triggers an inflationary period - otherwise the D universe will fizzle and die... Creating another universe from scratch, is a long drawn out process..who want's to sit around for that to happen?
May 19 2018
prev sibling parent reply Yuxuan Shui <yshuiv7 gmail.com> writes:
On Sunday, 20 May 2018 at 00:05:39 UTC, Jonathan M Davis wrote:
 because it tends to become very difficult to get right in all 
 cases and results in situations where the programmer is forced 
 to do something in order to make the compiler shut up
Well, doesn't this post show exactly this problem, and that's because the compiler is too dumb? Making the compiler smarter will only decrease the number of these cases.
May 20 2018
next sibling parent Daniel N <no public.email> writes:
On Sunday, 20 May 2018 at 10:56:27 UTC, Yuxuan Shui wrote:
 On Sunday, 20 May 2018 at 00:05:39 UTC, Jonathan M Davis wrote:
 because it tends to become very difficult to get right in all 
 cases and results in situations where the programmer is forced 
 to do something in order to make the compiler shut up
Well, doesn't this post show exactly this problem, and that's because the compiler is too dumb? Making the compiler smarter will only decrease the number of these cases.
There is one construct which is guaranteed to run at the end... this(ExceptionType t, long rowsNum, string file = __FILE__, size_t line = __LINE__) pure safe { type = t; string msg; scope(exit) super(msg, file, line); // w00t
May 20 2018
prev sibling next sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Sunday, May 20, 2018 10:56:27 Yuxuan Shui via Digitalmars-d wrote:
 On Sunday, 20 May 2018 at 00:05:39 UTC, Jonathan M Davis wrote:
 because it tends to become very difficult to get right in all
 cases and results in situations where the programmer is forced
 to do something in order to make the compiler shut up
Well, doesn't this post show exactly this problem, and that's because the compiler is too dumb? Making the compiler smarter will only decrease the number of these cases.
Well, constructors are one of the few places that the compiler attempts flow analysis for stuff other than optimization, because it pretty much has to in order to do what the language needs. And no, it's not very sophisticated about it, because it's simpler to guarantee correctness that way. It also highlights why Walter is usually against doing much in the way of flow analysis. By designing the language such that it doesn't need much flow analysis, you mostly avoid problems like this. Unfortunately, it becomes more or less impossible to completely avoid it in constructors when you have const or immutable members, so the compiler does have to do some flow analysis in constructors. And it seems that Walter's solution in this sort of situation is to err on the side of having the compiler be stupid in order to avoid better guarantee correctness. Not being a compiler expert, I can't really comment on what the best approach would be here, but I know that Walter is typically against flow analysis at the semantic pass level precisely because it's very hard to get right, and it's always a battle between having it be sophisticated enough to not get in the programmers way and having it actually be guaranteed to be correct. As I understand it, flow analysis in stuff like the optimizer is _much_ easier, because the constructs you're dealing with are much easier. That's also why Walter and Andrei really like to design advanced language features in terms of lowering into simpler features (e.g. the use of destructors and scope statments all get lowered to try-catch-finally blocks). It's much easier to guarantee correctness with simpler features. As for this particular case, I expect that the best course of action is to report it in bugzilla and see what Walter thinks is the best approach. I can comment on Walter's basic approach and reasoning based on what he's said about these issues in the past, but I can't way what his response would be to this particular example. - Jonathan M Davis
May 20 2018
parent Yuxuan Shui <yshuiv7 gmail.com> writes:
On Sunday, 20 May 2018 at 14:39:28 UTC, Jonathan M Davis wrote:
 Well, constructors are one of the few places that the compiler 
 attempts flow analysis for stuff other than optimization, 
 because it pretty much has to in order to do what the language 
 needs. And no, it's not very sophisticated about it, because 
 it's simpler to guarantee correctness that way. It also 
 highlights why Walter is usually against doing much in the way 
 of flow analysis. By designing the language such that it 
 doesn't need much flow analysis, you mostly avoid problems like 
 this. Unfortunately, it becomes more or less impossible to 
 completely avoid it in constructors when you have const or 
 immutable members, so the compiler does have to do some flow 
 analysis in constructors. And it seems that Walter's solution 
 in this sort of situation is to err on the side of having the 
 compiler be stupid in order to avoid better guarantee 
 correctness.

 Not being a compiler expert, I can't really comment on what the 
 best approach would be here, but I know that Walter is 
 typically against flow analysis at the semantic pass level 
 precisely because it's very hard to get right, and it's always 
 a battle between having it be sophisticated enough to not get 
 in the programmers way and having it actually be guaranteed to 
 be correct. As I understand it, flow analysis in stuff like the 
 optimizer is _much_ easier, because the constructs you're 
 dealing with are much easier. That's also why Walter and Andrei 
 really like to design advanced language features in terms of 
 lowering into simpler features (e.g. the use of destructors and 
 scope statments all get lowered to try-catch-finally blocks). 
 It's much easier to guarantee correctness with simpler features.

 As for this particular case, I expect that the best course of 
 action is to report it in bugzilla and see what Walter thinks 
 is the best approach. I can comment on Walter's basic approach 
 and reasoning based on what he's said about these issues in the 
 past, but I can't way what his response would be to this 
 particular example.

 - Jonathan M Davis
I would argue that the best approach is to design the language to avoid flow analysis as much as possible. But for places that need it, the compiler should do as best as it can.
May 20 2018
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 5/20/18 6:56 AM, Yuxuan Shui wrote:
 On Sunday, 20 May 2018 at 00:05:39 UTC, Jonathan M Davis wrote:
 because it tends to become very difficult to get right in all cases 
 and results in situations where the programmer is forced to do 
 something in order to make the compiler shut up
Well, doesn't this post show exactly this problem, and that's because the compiler is too dumb? Making the compiler smarter will only decrease the number of these cases.
There is something to be said for keeping the compiler dumb: 1. Dumb is easy to implement, explain, and understand -- if you set the bar low then more compilers will be able to handle the use cases. Having code that compiles with all available compilers is better than something that you need a specific "really smart" compiler to work. 2. No matter how smart you make the compiler, you will get into situations that it can't figure out (halting problem). If you are going to have some situations that it doesn't handle, then it's really just a matter of where to draw the line. D has this problem with forward references -- it's a never ending battle of shuffling things around sometimes. The smarter you get, the more odd and difficult to deal with the cases that won't work become. With inner functions, it's really easy to satisfy the compiler here. You just have to make a few changes in your code, I don't see it being a huge problem. I've been using Swift in the past few years quite a bit, and it always amuses me when it can't figure out some kind of inference that seems trivial, but it just gives up because the compiler takes too long to determine: "This [one line] statement is too difficult, please split into multiple statements." This is the kind of stuff you would be encountering. -Steve
May 21 2018
next sibling parent reply Yuxuan Shui <yshuiv7 gmail.com> writes:
My response below might be a little off-topic.

On Monday, 21 May 2018 at 13:06:14 UTC, Steven Schveighoffer 
wrote:
 [snip]

 There is something to be said for keeping the compiler dumb:

 1. Dumb is easy to implement, explain, and understand -- if you 
 set the bar low then more compilers will be able to handle the 
 use cases. Having code that compiles with all available 
 compilers is better than something that you need a specific 
 "really smart" compiler to work.
This would have been a fair point if there is more than one working D frontend right now. Maybe you are arguing the bar of D could be lower? Then the problem of where to draw the line pops up again. "Being dumb" couldn't be a goal of the language, right?
 2. No matter how smart you make the compiler, you will get into 
 situations that it can't figure out (halting problem).
True.
 If you are going to have some situations that it doesn't 
 handle, then it's really just a matter of where to draw the 
 line. D has this problem with forward references -- it's a 
 never ending battle of shuffling things around sometimes. The 
 smarter you get, the more odd and difficult to deal with the 
 cases that won't work become.
I would argue this is not because the compiler is too smart. This is because the behavior of the compiler is not pinned down. How D resolve forward references is not well documented, so when problem occurs you have to guess (or read the compiler source code, like a real man) to figure out how to solve it.
 With inner functions, it's really easy to satisfy the compiler 
 here. You just have to make a few changes in your code, I don't 
 see it being a huge problem.
Not a huge problem, but certainly a rough edge that might make someone think D is an unrefined language.
 I've been using Swift in the past few years quite a bit, and it 
 always amuses me when it can't figure out some kind of 
 inference that seems trivial, but it just gives up because the 
 compiler takes too long to determine: "This [one line] 
 statement is too difficult, please split into multiple 
 statements." This is the kind of stuff you would be 
 encountering.
Not sure if this is another case of compiler being not smart enough? And the solution seems to be pretty simple here.
 -Steve
May 21 2018
parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 5/21/18 4:29 PM, Yuxuan Shui wrote:
 My response below might be a little off-topic.
 
 On Monday, 21 May 2018 at 13:06:14 UTC, Steven Schveighoffer wrote:
 [snip]

 There is something to be said for keeping the compiler dumb:

 1. Dumb is easy to implement, explain, and understand -- if you set 
 the bar low then more compilers will be able to handle the use cases. 
 Having code that compiles with all available compilers is better than 
 something that you need a specific "really smart" compiler to work.
This would have been a fair point if there is more than one working D frontend right now. Maybe you are arguing the bar of D could be lower? Then the problem of where to draw the line pops up again. "Being dumb" couldn't be a goal of the language, right?
There are at least two other incomplete front ends. One by deadalnix (sdc) and one by Timon Gehr. But surely, if we got it right in the main front end, such techniques could be done in others right? Well, the problem simply is that I don't think there is a magic bullet here. We will have situations that are clear to a human that all paths call the super ctor, but aren't clear to some compilers. In that case, the language is different based on which compiler you might use. Rather than it be dependent on approximating a solution to an insolvable problem, we can simply say the *minimum* is this, and we KNOW that can be implemented. In turn, we also know that D gives you the tools to make it easy to conform to these requirements.
 If you are going to have some situations that it doesn't handle, then 
 it's really just a matter of where to draw the line. D has this 
 problem with forward references -- it's a never ending battle of 
 shuffling things around sometimes. The smarter you get, the more odd 
 and difficult to deal with the cases that won't work become.
I would argue this is not because the compiler is too smart. This is because the behavior of the compiler is not pinned down. How D resolve forward references is not well documented, so when problem occurs you have to guess (or read the compiler source code, like a real man) to figure out how to solve it.
I know Timon's front end handles a crazy amount of forward references. I've sat next to him at previous dconfs and he periodically shows me stuff his front end can handle, and it's insane. But in the meantime, the situation is not straightforward with forward references, and I'd fear that opening the gates to more flow analysis allowances would continue with those games.
 With inner functions, it's really easy to satisfy the compiler here. 
 You just have to make a few changes in your code, I don't see it being 
 a huge problem.
Not a huge problem, but certainly a rough edge that might make someone think D is an unrefined language.
Agreed, it is cool when your compiler tells you bugs like a variable is used before it's assigned, etc.
 
 I've been using Swift in the past few years quite a bit, and it always 
 amuses me when it can't figure out some kind of inference that seems 
 trivial, but it just gives up because the compiler takes too long to 
 determine: "This [one line] statement is too difficult, please split 
 into multiple statements." This is the kind of stuff you would be 
 encountering.
Not sure if this is another case of compiler being not smart enough? And the solution seems to be pretty simple here.
I believe it's due to the goal of "we're going to infer ALL THE TYPES!" hitting the reality of actual code that makes it not that simple, or exponential performance to really get the answer. Stuff that's painfully obvious to you or me is not so obvious to the compiler that has to actually prove it. That being said, I haven't used swift much lately, but I don't remember this happening much to me in the recent past. So maybe they have gotten better at it or solved it. -Steve
May 21 2018
prev sibling parent Yuxuan Shui <yshuiv7 gmail.com> writes:
 I've been using Swift in the past few years quite a bit, and it 
 always amuses me when it can't figure out some kind of 
 inference that seems trivial, but it just gives up because the 
 compiler takes too long to determine: "This [one line] 
 statement is too difficult, please split into multiple 
 statements." This is the kind of stuff you would be 
 encountering.
Clarification to my last point. I'm saying Swift's compiler is not smart enough, because other type inference languages doesn't seem to have this weird limitation. Worst case is they can't infer the type, then they fail back to not inferring, which is not worse than not having type inference.
 -Steve
May 21 2018