digitalmars.D - Fun surprising things
- bauss (22/22) Oct 31 2018 What's the output of this program? (Try to figure it out without
- rikki cattermole (32/32) Oct 31 2018 There isn't really any reason for it to be like this.
- Stanislav Blinov (3/7) Oct 31 2018 So indeed, both answers are "right".
- Steven Schveighoffer (14/25) Oct 31 2018 No, the correct answer is "01", according to left to right evaluation.
- Stanislav Blinov (10/37) Oct 31 2018 Not in this case, no.
- Timon Gehr (2/13) Oct 31 2018 I think you are the one who is misreading the spec here.
- Stanislav Blinov (3/4) Nov 03 2018 Indeed. I'm sorry, I'm gonna go stand in that shaming corner for
- Rubn (10/26) Oct 31 2018 What you quoted only relates to "AssignExpression", that means in
- Patrick Schluter (6/28) Oct 31 2018 01 is the other possible result. It all depends in what order a
- Patrick Schluter (3/38) Oct 31 2018 And I just checked, ldc gives 01 as response.
- Eugene Wissner (3/4) Oct 31 2018 and gdc "-10"
- Timon Gehr (4/40) Oct 31 2018 No, the spec says that 01 is the only allowed result.
- Kagamin (6/10) Nov 02 2018 In C function call is a sequence point, undefined order applies
- Patrick Schluter (35/46) Nov 02 2018 Yes, but irrelevant here. f(g(x), h(y)) doesn't mandate in which
- Johan Engelen (9/13) Nov 03 2018 Indeed.
- bachmeier (4/26) Oct 31 2018 Hopefully the pain of working with such code teaches one to not
- Jonathan Marler (2/35) Oct 31 2018 https://www.youtube.com/watch?v=lbp6vwdnE0k&start=1296
- Nick Sabalausky (Abscissa) (12/27) Oct 31 2018 I'm not sure I understand the point here. I mean, who writes code like
- Neia Neutuladh (23/51) Oct 31 2018 class Connection
- Jonathan M Davis (17/19) Oct 31 2018 The spec defines left-to-right evaluation, but since _most_ programming
- Brad Roberts (4/23) Nov 01 2018 That's a not unreasonable argument for not specifying the order of
- bauss (5/24) Nov 01 2018 The point is not what the functions do, but the order of
- Jonathan M Davis (12/39) Nov 01 2018 Oh, since the spec says that the order is defined, if the implementation
What's the output of this program? (Try to figure it out without running it.) ``` int c = 0; int a() { return c++; } int b() { return c--; } void main() { import std.conv : to; import std.stdio : writeln; writeln(to!string(a) ~ to!string(b)); } ``` If your answer is "10" then you're wrong. You can get the result and answer here: https://run.dlang.io/is/idZurR
Oct 31 2018
There isn't really any reason for it to be like this. Assembly: .text._Dmain segment assume CS:.text._Dmain _Dmain: push RBP mov RBP,RSP sub RSP,010h call int onlineapp.b() PLT32 mov RDI,RAX call pure nothrow safe immutable(char)[] std.conv.to!(immutable(char)[]).to!(int).to(int) PLT32 mov RCX,RAX mov R8,RDX mov -010h[RBP],RCX mov -8[RBP],R8 call int onlineapp.a() PLT32 mov RDI,RAX call pure nothrow safe immutable(char)[] std.conv.to!(immutable(char)[]).to!(int).to(int) PLT32 mov RSI,RAX mov R8,-8[RBP] mov RCX,-010h[RBP] mov RDI,TypeInfo_Aya.__init GOTPCREL[RIP] call _d_arraycatT PLT32 mov RDI,RAX mov RSI,RDX call safe void std.stdio.writeln!(immutable(char)[]).writeln(immutable(char)[]) PLT32 xor EAX,EAX leave ret
Oct 31 2018
On Wednesday, 31 October 2018 at 14:00:14 UTC, bauss wrote:If your answer is "10" then you're wrong.https://dlang.org/spec/expression.html#order-of-evaluation2. Implementation Defined: The order of evaluation of the operands of AssignExpression. ...So indeed, both answers are "right".
Oct 31 2018
On 10/31/18 10:18 AM, Stanislav Blinov wrote:On Wednesday, 31 October 2018 at 14:00:14 UTC, bauss wrote:No, the correct answer is "01", according to left to right evaluation. a should be evaluated first, which returns 0, and increments c by 1. Then b is evaluated, returning 1, and decrementing c by 1. But the assembly shows that this binary expression is evaluated right to left, which is not what the spec says. BUT, the lowering in the compiler could change arr1 ~ arr2 to a function call (arrayCat(arr1, arr2)), which then allows the compiler to evaluate in right to left order. So the inconsistency in the spec ("binary expressions are left to right", "function arguments are implementation defined order") leaves a gaping hole. What happens when a binary expression lowers to a function call? -SteveIf your answer is "10" then you're wrong.https://dlang.org/spec/expression.html#order-of-evaluation2. Implementation Defined: The order of evaluation of the operands of AssignExpression. ...So indeed, both answers are "right".
Oct 31 2018
On Wednesday, 31 October 2018 at 15:00:26 UTC, Steven Schveighoffer wrote:On 10/31/18 10:18 AM, Stanislav Blinov wrote:Not in this case, no.On Wednesday, 31 October 2018 at 14:00:14 UTC, bauss wrote:No, the correct answer is "01", according to left to right evaluation. a should be evaluated first, which returns 0, and increments c by 1.If your answer is "10" then you're wrong.https://dlang.org/spec/expression.html#order-of-evaluation2. Implementation Defined: The order of evaluation of the operands of AssignExpression. ...So indeed, both answers are "right".Then b is evaluated, returning 1, and decrementing c by 1. But the assembly shows that this binary expression is evaluated right to left, which is not what the spec says. BUT, the lowering in the compiler could change arr1 ~ arr2 to a function call (arrayCat(arr1, arr2)), which then allows the compiler to evaluate in right to left order.Could, or could not. It's implementation-defined.So the inconsistency in the spec ("binary expressions are left to right", "function arguments are implementation defined order") leaves a gaping hole. What happens when a binary expression lowers to a function call?You're misreading the spec. The relevant part is the one I quoted. There's no left-to-right evaluation rule here. It's not a binary expression, it's an argument list; in this case - one argument, which is a CatExpression, which is an AssignExpression, the order of evaluation of it's operands is implementation-defined.
Oct 31 2018
On 31.10.18 18:28, Stanislav Blinov wrote:I think you are the one who is misreading the spec here.So the inconsistency in the spec ("binary expressions are left to right", "function arguments are implementation defined order") leaves a gaping hole. What happens when a binary expression lowers to a function call?You're misreading the spec. The relevant part is the one I quoted. There's no left-to-right evaluation rule here. It's not a binary expression, it's an argument list; in this case - one argument, which is a CatExpression, which is an AssignExpression, the order of evaluation of it's operands is implementation-defined.
Oct 31 2018
On Wednesday, 31 October 2018 at 22:54:50 UTC, Timon Gehr wrote:I think you are the one who is misreading the spec here.Indeed. I'm sorry, I'm gonna go stand in that shaming corner for a while...
Nov 03 2018
On Wednesday, 31 October 2018 at 17:28:43 UTC, Stanislav Blinov wrote:What you quoted only relates to "AssignExpression", that means in the following case: a() += b(); Either a() or b() can be evaluated first, it is not defined. Ultimately what is being evaluated is: opBinary!"~"(to!string(a()), to!string(b())); Which the spec clearly specifies is calculated in left to right order:So the inconsistency in the spec ("binary expressions are left to right", "function arguments are implementation defined order") leaves a gaping hole. What happens when a binary expression lowers to a function call?You're misreading the spec. The relevant part is the one I quoted. There's no left-to-right evaluation rule here. It's not a binary expression, it's an argument list; in this case - one argument, which is a CatExpression, which is an AssignExpression, the order of evaluation of it's operands is implementation-defined.Binary expressions are evaluated in strictly left-to-right order. Function arguments are evaluated in strictly left-to-right order for functions with extern (D) linkage. assert(text(++i, ++i) == "1415"); // left to right evaluation of arguments
Oct 31 2018
On Wednesday, 31 October 2018 at 14:00:14 UTC, bauss wrote:What's the output of this program? (Try to figure it out without running it.) ``` int c = 0; int a() { return c++; } int b() { return c--; } void main() { import std.conv : to; import std.stdio : writeln; writeln(to!string(a) ~ to!string(b)); } ``` If your answer is "10" then you're wrong. You can get the result and answer here: https://run.dlang.io/is/idZurR01 is the other possible result. It all depends in what order a and b are called. ~ is not a sequence point (does D even have that typical C notion of sequence points?) so the order of evaluation is at the discretion of the compiler. therefore -10 or 01 are both right.
Oct 31 2018
On Wednesday, 31 October 2018 at 14:54:48 UTC, Patrick Schluter wrote:On Wednesday, 31 October 2018 at 14:00:14 UTC, bauss wrote:And I just checked, ldc gives 01 as response.What's the output of this program? (Try to figure it out without running it.) ``` int c = 0; int a() { return c++; } int b() { return c--; } void main() { import std.conv : to; import std.stdio : writeln; writeln(to!string(a) ~ to!string(b)); } ``` If your answer is "10" then you're wrong. You can get the result and answer here: https://run.dlang.io/is/idZurR01 is the other possible result. It all depends in what order a and b are called. ~ is not a sequence point (does D even have that typical C notion of sequence points?) so the order of evaluation is at the discretion of the compiler. therefore -10 or 01 are both right.
Oct 31 2018
On Wednesday, 31 October 2018 at 15:00:52 UTC, Patrick Schluter wrote:And I just checked, ldc gives 01 as response.and gdc "-10"
Oct 31 2018
On 31.10.18 15:54, Patrick Schluter wrote:On Wednesday, 31 October 2018 at 14:00:14 UTC, bauss wrote:No, the spec says that 01 is the only allowed result. https://dlang.org/spec/expression.html#order-of-evaluation Concatenation is a binary expression.What's the output of this program? (Try to figure it out without running it.) ``` int c = 0; int a() { return c++; } int b() { return c--; } void main() { import std.conv : to; import std.stdio : writeln; writeln(to!string(a) ~ to!string(b)); } ``` If your answer is "10" then you're wrong. You can get the result and answer here: https://run.dlang.io/is/idZurR01 is the other possible result. It all depends in what order a and b are called. ~ is not a sequence point (does D even have that typical C notion of sequence points?) so the order of evaluation is at the discretion of the compiler. therefore -10 or 01 are both right.
Oct 31 2018
On Wednesday, 31 October 2018 at 14:54:48 UTC, Patrick Schluter wrote:01 is the other possible result. It all depends in what order a and b are called. ~ is not a sequence point (does D even have that typical C notion of sequence points?) so the order of evaluation is at the discretion of the compiler.In C function call is a sequence point, undefined order applies only to expressions without sequence points. BTW to!string allocates memory from GC which involves a mutex lock, which can't possibly have undefined order.
Nov 02 2018
On Friday, 2 November 2018 at 08:15:28 UTC, Kagamin wrote:On Wednesday, 31 October 2018 at 14:54:48 UTC, Patrick Schluter wrote:Yes, but irrelevant here. f(g(x), h(y)) doesn't mandate in which order g(x) and h(y) are evaluated even though x will be evaluated before g is called and y before h is called. That's all the sequence point of function call can do (btw, I wouldn't rely, in C, on that sequence point as inlining often breaks it).01 is the other possible result. It all depends in what order a and b are called. ~ is not a sequence point (does D even have that typical C notion of sequence points?) so the order of evaluation is at the discretion of the compiler.In C function call is a sequence point, undefined order applies only to expressions without sequence points.BTW to!string allocates memory from GC which involves a mutex lock, which can't possibly have undefined order.Same remark, doesn't change anything. f(g(x), h(y)) only garantees these 2 orders push x sequence point call g push g(x) push y sequence point call h push h(y) sequence point call f or push y sequence point call h push h(y) push x sequence point call g push g(x) sequence point call f theoretically also parallel evaluation of g(x) and h(y) but in practice I've never seen it. But all this is moot as D is not C and the specs of D mandate the order of evaluation for ~. dmd and gdc clearly violate the specs and either the specs are loosened or the compiler is corrected.
Nov 02 2018
On Friday, 2 November 2018 at 09:27:50 UTC, Patrick Schluter wrote:But all this is moot as D is not C and the specs of D mandate the order of evaluation for ~. dmd and gdc clearly violate the specs and either the specs are loosened or the compiler is corrected.Indeed. We found this a very serious bug and made LDC respect this part of the language specification since version 1.8.0. If you still find cases where LDC does not respect strict left-to-right evaluation order, please file a bug with LDC, thanks! -Johan
Nov 03 2018
On Wednesday, 31 October 2018 at 14:00:14 UTC, bauss wrote:What's the output of this program? (Try to figure it out without running it.) ``` int c = 0; int a() { return c++; } int b() { return c--; } void main() { import std.conv : to; import std.stdio : writeln; writeln(to!string(a) ~ to!string(b)); } ``` If your answer is "10" then you're wrong. You can get the result and answer here: https://run.dlang.io/is/idZurRHopefully the pain of working with such code teaches one to not write such code. Yes, you can write FORTRAN in D, but that doesn't mean it's a good idea to do so.
Oct 31 2018
On Wednesday, 31 October 2018 at 16:05:47 UTC, bachmeier wrote:On Wednesday, 31 October 2018 at 14:00:14 UTC, bauss wrote:https://www.youtube.com/watch?v=lbp6vwdnE0k&start=1296What's the output of this program? (Try to figure it out without running it.) ``` int c = 0; int a() { return c++; } int b() { return c--; } void main() { import std.conv : to; import std.stdio : writeln; writeln(to!string(a) ~ to!string(b)); } ``` If your answer is "10" then you're wrong. You can get the result and answer here: https://run.dlang.io/is/idZurRHopefully the pain of working with such code teaches one to not write such code. Yes, you can write FORTRAN in D, but that doesn't mean it's a good idea to do so.
Oct 31 2018
On 10/31/18 10:00 AM, bauss wrote:What's the output of this program? (Try to figure it out without running it.) ``` int c = 0; int a() { return c++; } int b() { return c--; }I'm not sure I understand the point here. I mean, who writes code like that? Pre/Post-incement operators? Combined with globals? To me that just smells of trouble. So if the issue is that the above code should result in an error but currently doesn't, then...honestly, I'm totally onboard with that, because it definitely strikes me as bad code. But I'm unclear about the details. What *exact* part of it should be the error? To me, that's the part that's not obvious. Intuitively, it strikes me as as bad code, but to me, it's not obvious what *specifically* the compiler should be objecting to. So, at least for me, spelling this out in more detail would really help.
Oct 31 2018
On Thu, 01 Nov 2018 00:39:17 -0400, Nick Sabalausky (Abscissa) wrote:On 10/31/18 10:00 AM, bauss wrote:class Connection { Socket socket; int readInt() { /* read an int from the socket somehow */ } float readFloat() { /* read a float from the socket */ } void doSomethingFunky() { writeln(to!string(readInt()) ~ to!string(readFloat())); } } It's not great, but it doesn't deal with pre/post increment operators or global variables. The point is that both sides of the expression have side effects altering the same data. What happens should be well-defined. A global variable and increment operators are condensed ways of showing what's going on.What's the output of this program? (Try to figure it out without running it.) ``` int c = 0; int a() { return c++; } int b() { return c--; }I'm not sure I understand the point here. I mean, who writes code like that? Pre/Post-incement operators? Combined with globals? To me that just smells of trouble.So if the issue is that the above code should result in an error but currently doesn't, then...honestly, I'm totally onboard with that, because it definitely strikes me as bad code. But I'm unclear about the details. What *exact* part of it should be the error? To me, that's the part that's not obvious. Intuitively, it strikes me as as bad code, but to me, it's not obvious what *specifically* the compiler should be objecting to. So, at least for me, spelling this out in more detail would really help.If you don't introduce whole-program analysis, your error is that the operands are not pure / immutable. If you do introduce whole-program analysis, your error is that both sides of the expression modify the same mutable state, and the return value is dependent on that state. Except that's only applicable if the spec doesn't define the appropriate order of evaluation.
Oct 31 2018
On Wednesday, October 31, 2018 10:58:55 PM MDT Neia Neutuladh via Digitalmars-d wrote:Except that's only applicable if the spec doesn't define the appropriate order of evaluation.The spec defines left-to-right evaluation, but since _most_ programming languages don't define the order of evaluation so that the compiler can efficiently reorder operations, I'd honestly argue that it's just plain bad practice in general to rely on the order of evaluation of expressions like this. It's the sort of thing that's just begging for trouble. Sure, if D defines it, plays by its own rules properly, you understand its rules properly, and you write your code accordingly, you can theoretically avoid problems, but if you get in the habit of writing such code, you're just begging to shoot yourself in the foot as soon as you have to write code in any other language. And even within D, if the expression is complicated, the exact order of operations can get hard to understand. So, writing anything that's even vaguely like foo() + bar() where foo() or bar() depend on one another at all is just asking for it. It's a code smell, and it should be avoided. - Jonathan M Davis
Oct 31 2018
On 10/31/2018 10:57 PM, Jonathan M Davis via Digitalmars-d wrote:On Wednesday, October 31, 2018 10:58:55 PM MDT Neia Neutuladh via Digitalmars-d wrote:That's a not unreasonable argument for not specifying the order of evaluation. But that's irrelevant since D has defined the order so not following it is a bug that must be fixed.Except that's only applicable if the spec doesn't define the appropriate order of evaluation.The spec defines left-to-right evaluation, but since _most_ programming languages don't define the order of evaluation so that the compiler can efficiently reorder operations, I'd honestly argue that it's just plain bad practice in general to rely on the order of evaluation of expressions like this. It's the sort of thing that's just begging for trouble. Sure, if D defines it, plays by its own rules properly, you understand its rules properly, and you write your code accordingly, you can theoretically avoid problems, but if you get in the habit of writing such code, you're just begging to shoot yourself in the foot as soon as you have to write code in any other language. And even within D, if the expression is complicated, the exact order of operations can get hard to understand. So, writing anything that's even vaguely like foo() + bar() where foo() or bar() depend on one another at all is just asking for it. It's a code smell, and it should be avoided. - Jonathan M Davis
Nov 01 2018
On Thursday, 1 November 2018 at 04:39:17 UTC, Nick Sabalausky (Abscissa) wrote:On 10/31/18 10:00 AM, bauss wrote:The point is not what the functions do, but the order of evaluation. It was just a simple example to reproduce it.What's the output of this program? (Try to figure it out without running it.) ``` int c = 0; int a() { return c++; } int b() { return c--; }I'm not sure I understand the point here. I mean, who writes code like that? Pre/Post-incement operators? Combined with globals? To me that just smells of trouble.
Nov 01 2018
On Thursday, November 1, 2018 1:42:27 AM MDT Brad Roberts via Digitalmars-d wrote:On 10/31/2018 10:57 PM, Jonathan M Davis via Digitalmars-d wrote:Oh, since the spec says that the order is defined, if the implementation doesn't follow it, it should definitely be fixed. I definitely won't argue that. But just the same, any code that relies on it is just begging for trouble and is bad code IMHO. Though honestly, I expect that it's a bit of a nightmare on the implementation end of things to keep the order of evaluation correct when you start lowering one construct to another. That's no excuse. The spec needs to either be followed or changed, but it doesn't surprise me if such bugs exist. - Jonathan M DavisOn Wednesday, October 31, 2018 10:58:55 PM MDT Neia Neutuladh via Digitalmars-d wrote:That's a not unreasonable argument for not specifying the order of evaluation. But that's irrelevant since D has defined the order so not following it is a bug that must be fixed.Except that's only applicable if the spec doesn't define the appropriate order of evaluation.The spec defines left-to-right evaluation, but since _most_ programming languages don't define the order of evaluation so that the compiler can efficiently reorder operations, I'd honestly argue that it's just plain bad practice in general to rely on the order of evaluation of expressions like this. It's the sort of thing that's just begging for trouble. Sure, if D defines it, plays by its own rules properly, you understand its rules properly, and you write your code accordingly, you can theoretically avoid problems, but if you get in the habit of writing such code, you're just begging to shoot yourself in the foot as soon as you have to write code in any other language. And even within D, if the expression is complicated, the exact order of operations can get hard to understand. So, writing anything that's even vaguely like foo() + bar() where foo() or bar() depend on one another at all is just asking for it. It's a code smell, and it should be avoided. - Jonathan M Davis
Nov 01 2018