digitalmars.D - Increment / Decrement Operator Behavior
- "Xinok" <xinok live.com> Jun 04 2012
- simendsjo <simendsjo gmail.com> Jun 04 2012
- "Bernard Helyer" <b.helyer gmail.com> Jun 04 2012
- simendsjo <simendsjo gmail.com> Jun 04 2012
- "Xinok" <xinok live.com> Jun 04 2012
- "bearophile" <bearophileHUGS lycos.com> Jun 04 2012
- "Bernard Helyer" <b.helyer gmail.com> Jun 04 2012
- "Jonathan M Davis" <jmdavisProg gmx.com> Jun 04 2012
- "bearophile" <bearophileHUGS lycos.com> Jun 04 2012
- "Xinok" <xinok live.com> Jun 04 2012
- Kevin Cox <kevincox.ca gmail.com> Jun 04 2012
- Timon Gehr <timon.gehr gmx.ch> Jun 05 2012
- Mikael Lindsten <mikael lindsten.net> Jun 05 2012
- Dejan Lekic <dejan.lekic gmail.com> Jun 06 2012
- Iain Buclaw <ibuclaw ubuntu.com> Jun 06 2012
The increment and decrement operators are highly dependent on operator precedence and associativity. If the actions are performed in a different order than the developer presumed, it could cause unexpected behavior. I had a simple idea to change the behavior of this operator. It works for the postfix operators but not prefix. Take the following code: size_t i = 5; writeln(i--, i--, i--); As of now, this writes "543". With my idea, instead it would write, "555". Under the hood, the compiler would rewrite the code as: size_t i = 5; writeln(i, i, i); --i; --i; --i; It decrements the variable after the current statement. While not the norm, this behavior is at least predictable. For non-static variables, such as array elements, the compiler could store a temporary reference to the variable so it can decrement it afterwards. I'm not actually proposing we actually make this change. I simply thought it was a nifty idea worth sharing.
Jun 04 2012
On Mon, 04 Jun 2012 20:36:14 +0200, Xinok <xinok live.com> wrote:The increment and decrement operators are highly dependent on operator precedence and associativity. If the actions are performed in a different order than the developer presumed, it could cause unexpected behavior. I had a simple idea to change the behavior of this operator. It works for the postfix operators but not prefix. Take the following code: size_t i = 5; writeln(i--, i--, i--); As of now, this writes "543". With my idea, instead it would write, "555". Under the hood, the compiler would rewrite the code as: size_t i = 5; writeln(i, i, i); --i; --i; --i; It decrements the variable after the current statement. While not the norm, this behavior is at least predictable. For non-static variables, such as array elements, the compiler could store a temporary reference to the variable so it can decrement it afterwards. I'm not actually proposing we actually make this change. I simply thought it was a nifty idea worth sharing.
If I ever saw a construct like that, I would certainly test how that works, then rewrite it. I wouldn't find it natural with the new behavior either. I would expect "543" or "345". How often do you come across code like that? I think it's an anti-pattern, and shouldn't be encouraged even if it was easier to understand.
Jun 04 2012
If you find yourself using postfix increment/decrement operators in the same function call in multiple arguments, slap yourself firmly in the face and refactor that code.
Jun 04 2012
On Mon, 04 Jun 2012 20:57:11 +0200, simendsjo <simendsjo gmail.com> wrote:On Mon, 04 Jun 2012 20:36:14 +0200, Xinok <xinok live.com> wrote:The increment and decrement operators are highly dependent on operator precedence and associativity. If the actions are performed in a different order than the developer presumed, it could cause unexpected behavior. I had a simple idea to change the behavior of this operator. It works for the postfix operators but not prefix. Take the following code: size_t i = 5; writeln(i--, i--, i--); As of now, this writes "543". With my idea, instead it would write, "555". Under the hood, the compiler would rewrite the code as: size_t i = 5; writeln(i, i, i); --i; --i; --i; It decrements the variable after the current statement. While not the norm, this behavior is at least predictable. For non-static variables, such as array elements, the compiler could store a temporary reference to the variable so it can decrement it afterwards. I'm not actually proposing we actually make this change. I simply thought it was a nifty idea worth sharing.
If I ever saw a construct like that, I would certainly test how that works, then rewrite it. I wouldn't find it natural with the new behavior either. I would expect "543" or "345". How often do you come across code like that? I think it's an anti-pattern, and shouldn't be encouraged even if it was easier to understand.
Oh, and what should writeln(i++, ++i, ++i, i++) do? It is messy whatever the logic implementation.
Jun 04 2012
On Monday, 4 June 2012 at 20:08:57 UTC, simendsjo wrote:Oh, and what should writeln(i++, ++i, ++i, i++) do? It is messy whatever the logic implementation.
For prefix operators, it would be logical to perform the action before the statement, such as the code would be rewritten as: ++i ++i writeln(i, i, i, i) i++ i++ However, I already stated that it wouldn't work for prefix operators. Take this statement: ++foo(++i) There's no way to increment the return value of foo without calling foo first. This "logic" would only work for the postfix operators. I came up with the idea after refactoring this code: https://github.com/Xinok/XSort/blob/master/timsort.d#L111 Each call to mergeAt is followed by --stackLen. I could have used stackLen-- in the mergeAt statement instead, but I didn't want to rely on operator precedence for the correct behavior.
Jun 04 2012
Bernard Helyer:If you find yourself using postfix increment/decrement operators in the same function call in multiple arguments, slap yourself firmly in the face and refactor that code.
I think this is not acceptable, you can't rely on that, future D programers will not slap themselves and refactor their code. Some of the acceptable alternatives are: 1) Make post/pre increments return void. This avoid those troubles. I think Go language has chosen this. This is my preferred solution. 2) Turn that code into a syntax error for some other cause. 3) Design the language so post/pre increments give a defined effect on all D compilers on all CPUs. Walter since lot of time says this is planned for D. This leads to deterministic programs, but sometimes they are hard to understand and hard to translate (port) to other languages any way. Translating code to other languages is not irrelevant because D must be designed to make it easy to understand the semantics of the code. Bye, bearophile
Jun 04 2012
On Monday, 4 June 2012 at 20:44:42 UTC, bearophile wrote:Bernard Helyer:If you find yourself using postfix increment/decrement operators in the same function call in multiple arguments, slap yourself firmly in the face and refactor that code.
I think this is not acceptable, you can't rely on that, future D programers will not slap themselves and refactor their code. Some of the acceptable alternatives are: 1) Make post/pre increments return void. This avoid those troubles. I think Go language has chosen this. This is my preferred solution. 2) Turn that code into a syntax error for some other cause. 3) Design the language so post/pre increments give a defined effect on all D compilers on all CPUs. Walter since lot of time says this is planned for D. This leads to deterministic programs, but sometimes they are hard to understand and hard to translate (port) to other languages any way. Translating code to other languages is not irrelevant because D must be designed to make it easy to understand the semantics of the code. Bye, bearophile
If people can't be bothered to understand what they write, they can go hang.
Jun 04 2012
On Monday, June 04, 2012 23:22:26 Bernard Helyer wrote:On Monday, 4 June 2012 at 20:44:42 UTC, bearophile wrote:Bernard Helyer:If you find yourself using postfix increment/decrement operators in the same function call in multiple arguments, slap yourself firmly in the face and refactor that code.
I think this is not acceptable, you can't rely on that, future D programers will not slap themselves and refactor their code. Some of the acceptable alternatives are: 1) Make post/pre increments return void. This avoid those troubles. I think Go language has chosen this. This is my preferred solution. 2) Turn that code into a syntax error for some other cause. 3) Design the language so post/pre increments give a defined effect on all D compilers on all CPUs. Walter since lot of time says this is planned for D. This leads to deterministic programs, but sometimes they are hard to understand and hard to translate (port) to other languages any way. Translating code to other languages is not irrelevant because D must be designed to make it easy to understand the semantics of the code. Bye, bearophile
If people can't be bothered to understand what they write, they can go hang.
I think that Bernard is being a bit harsh, but in essence, I agree. Since the evaluation order of arguments is undefined, programmers should be aware of that and code accordingly. If they don't bother to learn, then they're going to get bitten, and that's life. Now, Walter _has_ expressed interest in changing it so that the order of evaluation for function arguments is fully defined as being left-to-right, which solves the issue. I'd still council against getting into the habit of writing code which relies on the order of evaluation for the arguments to a function, since it's so common for other languages not to define it (so that the compiler can better optimize the calls), and so getting into the habit of writing code which _does_ depend on the order of evalution for function arguments will cause you to write bad code you when you work in most other programming languages. As for treating pre or post-increment operators specially in some manner, that doesn't make sense. The problem is far more general than that. If we're going to change anything, it would be to make it so that the language itself defines the order of evaluation of function arguments as being left-to-right. - Jonathan M Davis
Jun 04 2012
Jonathan M Davis:If they don't bother to learn, then they're going to get bitten, and that's life.
A modern language must try to avoid common programmer mistakes, where possible (like in this case).As for treating pre or post-increment operators specially in some manner, that doesn't make sense. The problem is far more general than that. If we're going to change anything, it would be to make it so that the language itself defines the order of evaluation of function arguments as being left-to-right.
Probably I have expressed myself badly there, sorry. I'd like to see function calls fixed as Walter has stated. And regarding pre/post de/increment operators, I find them handy, but I have seen _so much_ C/C++ code that abuses them that maybe I'd like them to return void, as in Go. Bye, bearophile
Jun 04 2012
On Monday, 4 June 2012 at 20:44:42 UTC, bearophile wrote:1) Make post/pre increments return void. This avoid those troubles. I think Go language has chosen this. This is my preferred solution.
language? For me anyways, the whole point of these operators is to use them in expressions. Otherwise, why not simply write (i+=1)?
Jun 04 2012
--000e0ce0252614c80b04c1af6a05 Content-Type: text/plain; charset=UTF-8 On Jun 4, 2012 8:43 PM, "Xinok" <xinok live.com> wrote:I wonder in that case, is it even worth including in the language? For me
Otherwise, why not simply write (i+=1)? For pointers they are useful because they go up in units not bytes (although addition often does too). --000e0ce0252614c80b04c1af6a05 Content-Type: text/html; charset=UTF-8 <p><br> On Jun 4, 2012 8:43 PM, "Xinok" <<a href="mailto:xinok live.com">xinok live.com</a>> wrote:<br> ><br> > I wonder in that case, is it even worth including in the language? For me anyways, the whole point of these operators is to use them in expressions. Otherwise, why not simply write (i+=1)?</p> <p>For pointers they are useful because they go up in units not bytes (although addition often does too).<br> </p> --000e0ce0252614c80b04c1af6a05--
Jun 04 2012
On 06/04/2012 08:36 PM, Xinok wrote:The increment and decrement operators are highly dependent on operator precedence and associativity. If the actions are performed in a different order than the developer presumed, it could cause unexpected behavior. I had a simple idea to change the behavior of this operator. It works for the postfix operators but not prefix. Take the following code: size_t i = 5; writeln(i--, i--, i--); As of now, this writes "543". With my idea, instead it would write, "555". Under the hood, the compiler would rewrite the code as: size_t i = 5; writeln(i, i, i); --i; --i; --i; It decrements the variable after the current statement. While not the norm, this behavior is at least predictable. For non-static variables, such as array elements, the compiler could store a temporary reference to the variable so it can decrement it afterwards. I'm not actually proposing we actually make this change. I simply thought it was a nifty idea worth sharing.
The behaviour the language requires is that the function call executes as if the parameters were evaluated from left to right. This is exactly the behaviour you observe. What is the problem you want to fix?
Jun 05 2012
--20cf306f7202de1fde04c1b55c91 Content-Type: text/plain; charset=ISO-8859-1 2012/6/5 Jonathan M Davis <jmdavisProg gmx.com>I think that Bernard is being a bit harsh, but in essence, I agree. Since the evaluation order of arguments is undefined, programmers should be aware of that and code accordingly. If they don't bother to learn, then they're going to get bitten, and that's life. Now, Walter _has_ expressed interest in changing it so that the order of evaluation for function arguments is fully defined as being left-to-right, which solves the issue. I'd still council against getting into the habit of writing code which relies on the order of evaluation for the arguments to a function, since it's so common for other languages not to define it (so that the compiler can better optimize the calls), and so getting into the habit of writing code which _does_ depend on the order of evalution for function arguments will cause you to write bad code you when you work in most other programming languages. As for treating pre or post-increment operators specially in some manner, that doesn't make sense. The problem is far more general than that. If we're going to change anything, it would be to make it so that the language itself defines the order of evaluation of function arguments as being left-to-right. - Jonathan M Davis
Agree completely! --20cf306f7202de1fde04c1b55c91 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <div class=3D"gmail_quote">2012/6/5 Jonathan M Davis <span dir=3D"ltr"><= <a href=3D"mailto:jmdavisProg gmx.com" target=3D"_blank">jmdavisProg gmx.co= m</a>></span><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8e= x;border-left:1px #ccc solid;padding-left:1ex"> <div class=3D"HOEnZb"><div class=3D"h5"> <br> </div></div>I think that Bernard is being a bit harsh, but in essence, I ag= ree. Since the<br> evaluation order of arguments is undefined, programmers should be aware of = that<br> and code accordingly. If they don't bother to learn, then they're g= oing to get<br> bitten, and that's life.<br> <br> Now, Walter _has_ expressed interest in changing it so that the order of<br=
br> which solves the issue. I'd still council against getting into the habi= t of<br> writing code which relies on the order of evaluation for the arguments to a= <br> function, since it's so common for other languages not to define it (so= that<br> the compiler can better optimize the calls), and so getting into the habit = of<br> writing code which _does_ depend on the order of evalution for function<br> arguments will cause you to write bad code you when you work in most other<= br> programming languages.<br> <br> As for treating pre or post-increment operators specially in some manner, t= hat<br> doesn't make sense. The problem is far more general than that. If we= 9;re going<br> to change anything, it would be to make it so that the language itself defi= nes<br> the order of evaluation of function arguments as being left-to-right.<br> <span class=3D"HOEnZb"><font color=3D"#888888"><br> - Jonathan M Davis<br> </font></span></blockquote></div><br><div>Agree completely!</div><div><br><= /div> --20cf306f7202de1fde04c1b55c91--
Jun 05 2012
On Tue, 05 Jun 2012 10:23:18 +0200, Mikael Lindsten wrote:2012/6/5 Jonathan M Davis <jmdavisProg gmx.com>I think that Bernard is being a bit harsh, but in essence, I agree. Since the evaluation order of arguments is undefined, programmers should be aware of that and code accordingly. If they don't bother to learn, then they're going to get bitten, and that's life. Now, Walter _has_ expressed interest in changing it so that the order of evaluation for function arguments is fully defined as being left-to-right, which solves the issue. I'd still council against getting into the habit of writing code which relies on the order of evaluation for the arguments to a function, since it's so common for other languages not to define it (so that the compiler can better optimize the calls), and so getting into the habit of writing code which _does_ depend on the order of evalution for function arguments will cause you to write bad code you when you work in most other programming languages. As for treating pre or post-increment operators specially in some manner, that doesn't make sense. The problem is far more general than that. If we're going to change anything, it would be to make it so that the language itself defines the order of evaluation of function arguments as being left-to-right. - Jonathan M Davis
<div class="gmail_quote">2012/6/5 Jonathan M Davis <span dir="ltr"><<a href="mailto:jmdavisProg gmx.com" target="_blank">jmdavisProg gmx.com</a>></span><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> <div class="HOEnZb"><div class="h5"> <br> </div></div>I think that Bernard is being a bit harsh, but in essence, I agree. Since the<br> evaluation order of arguments is undefined, programmers should be aware of that<br> and code accordingly. If they don't bother to learn, then they're going to get<br> bitten, and that's life.<br> <br> Now, Walter _has_ expressed interest in changing it so that the order of<br> evaluation for function arguments is fully defined as being left-to-right,<br> which solves the issue. I'd still council against getting into the habit of<br> writing code which relies on the order of evaluation for the arguments to a<br> function, since it's so common for other languages not to define it (so that<br> the compiler can better optimize the calls), and so getting into the habit of<br> writing code which _does_ depend on the order of evalution for function<br> arguments will cause you to write bad code you when you work in most other<br> programming languages.<br> <br> As for treating pre or post-increment operators specially in some manner, that<br> doesn't make sense. The problem is far more general than that. If we're going<br> to change anything, it would be to make it so that the language itself defines<br> the order of evaluation of function arguments as being left-to-right.<br> <span class="HOEnZb"><font color="#888888"><br> - Jonathan M Davis<br> </font></span></blockquote></div><br><div>Agree completely!</div><div><br></div>
Ah noes, my eyes... HTML code... :-( -- Dejan Lekic mailto:dejan.lekic(a)gmail.com http://dejan.lekic.org
Jun 06 2012
On 4 June 2012 23:37, Jonathan M Davis <jmdavisProg gmx.com> wrote:On Monday, June 04, 2012 23:22:26 Bernard Helyer wrote:On Monday, 4 June 2012 at 20:44:42 UTC, bearophile wrote:Bernard Helyer:If you find yourself using postfix increment/decrement operators in the same function call in multiple arguments, slap yourself firmly in the face and refactor that code.
I think this is not acceptable, you can't rely on that, future D programers will not slap themselves and refactor their code. Some of the acceptable alternatives are: 1) Make post/pre increments return void. This avoid those troubles. I think Go language has chosen this. This is my preferred solution. 2) Turn that code into a syntax error for some other cause. 3) Design the language so post/pre increments give a defined effect on all D compilers on all CPUs. Walter since lot of time says this is planned for D. This leads to deterministic programs, but sometimes they are hard to understand and hard to translate (port) to other languages any way. Translating code to other languages is not irrelevant because D must be designed to make it easy to understand the semantics of the code. Bye, bearophile
If people can't be bothered to understand what they write, they can go hang.
I think that Bernard is being a bit harsh, but in essence, I agree. Since the evaluation order of arguments is undefined, programmers should be aware of that and code accordingly. If they don't bother to learn, then they're going to get bitten, and that's life. Now, Walter _has_ expressed interest in changing it so that the order of evaluation for function arguments is fully defined as being left-to-right, which solves the issue. I'd still council against getting into the habit of writing code which relies on the order of evaluation for the arguments to a function, since it's so common for other languages not to define it (so that the compiler can better optimize the calls), and so getting into the habit of writing code which _does_ depend on the order of evalution for function arguments will cause you to write bad code you when you work in most other programming languages. As for treating pre or post-increment operators specially in some manner, that doesn't make sense. The problem is far more general than that. If we're going to change anything, it would be to make it so that the language itself defines the order of evaluation of function arguments as being left-to-right.
"the language itself defines the order of evaluation of function arguments as being left-to-right" ... if the calling convention defines it. For extern(D) the way you can expect order of evaluation to work in gdc generated code - for instance - is that each argument is evaluated from left to right, and if it has any side effects, then it is stored into a temporary prior to calling the function. For extern(C) the order of evaluation is actually defined by the underlying architecture. For example, i386 evaluates right-to-left, however other architectures (ie: ARM) perform left-to-right evaluation of function arguments. Incidentally, I know there are a few tests in the testsuite that depend on the i386 behaviour, but that is something else to worry about. Regards -- Iain Buclaw *(p < e ? p++ : p) = (c & 0x0f) + '0';
Jun 06 2012









simendsjo <simendsjo gmail.com> 