A More Creative Post Increment



  • Ran into the following gem recently while digging through some Java code in one of our company's web applications.

       <FONT face="Courier New">selected = selected++;</FONT>

    Well, at least he sorta gets it.



  • Maybe he's just cautious. Sometimes those unary operators don't take.

    (joke)



  • @wgh said:

    Ran into the following gem recently while digging through some Java code in one of our company's web applications.

       <font face="Courier New">selected = selected++;</font>

    Well, at least he sorta gets it.



    Uhhhh you should make sure you track that dev down. That works by accident. Make sure they know what's going on. (assignment, then incrementation.... lucky that he's incrementing the variable being assigned)


  • @GoatCheez said:

    @wgh said:

    Ran into the following gem recently while digging through some Java code in one of our company's web applications.

       <font face="Courier New">selected = selected++;</font>

    Well, at least he sorta gets it.



    Uhhhh you should make sure you track that dev down. That works by accident. Make sure they know what's going on. (assignment, then incrementation.... lucky that he's incrementing the variable being assigned)

    Actually that doesn't work. The variable selected will never be incremented in that code! If you don't believe me try it for yourself. You need to remove the assignment and bring this to the attention of the developers (most of them probably don't understand why this doesn't work.

    What actually happens here is

    • The value of selected is resolved.
    • The value of selected is incremented.
    • The value that was previously resolved (the non-incremented value of selected) is assigned back to selected
    In this case the '++' operator is a lost operation and no increment actually takes place.



  • @smbell said:


    What actually happens here is

    • The value of selected is resolved.
    • The value of selected is incremented.
    • The value that was previously resolved (the non-incremented value of selected) is assigned back to selected
    In this case the '++' operator is a lost operation and no increment actually takes place.



    Strange.  I woulda guessed that step #2 would happen before step #3, so I tried it out in PHP.  You're 100% correct.

    Honestly, I'd cut the guy a little slack.  There aren't many things in C-esqe syntax that work like the increment operator.


  • Yup.  At least in c++, that's correct.

    #include <iostream>

    int main() {
        int a = 42;
        a = a++;
       
        std::cout << a << std::endl;
        return 0;
    }


    This displays 42.



  • @shadowman said:

    Yup.  At least in c++, that's correct.

    #include <iostream>

    int main() {
        int a = 42;
        a = a++; // whups
       
        std::cout << a << std::endl;
        return 0;
    }


    This displays 42.


    ...on your machine, compiler, and configuration.  The statement marked "whups" has, formally, undefined behaviour.  The program could print 42, 43, 41, format your hard drive, mail nasty pictures of yourself and a goat to your boss, or make demons fly out your nose and still fall within the C++ specification.



  • @merreborn said:


    Honestly, I'd cut the guy a little slack.  There aren't many things in C-esqe syntax that work like the increment operator.

    I agree. I'd bring it up as a good lesson for everybody.



  • @Angstrom said:

    @shadowman said:
    Yup.  At least in c++, that's correct.

    #include <iostream>

    int main() {
        int a = 42;
        a = a++; // whups
       
        std::cout << a << std::endl;
        return 0;
    }


    This displays 42.


    ...on your machine, compiler, and configuration.  The statement marked "whups" has, formally, undefined behaviour.  The program could print 42, 43, 41, format your hard drive, mail nasty pictures of yourself and a goat to your boss, or make demons fly out your nose and still fall within the C++ specification.

    In C/C++ (I'm pretty sure both) this has undefined behaviour, but in Java it's behaviour is specifically ordered. Basically the unary increment operator has a higher precedent than the assignment operator. I've seen it work both ways with various C++ compilers (although I can't remember it ever mailing those pictures to my boss, guess I've been lucky).



  • @smbell said:

    @merreborn said:

    Honestly, I'd cut the guy a little slack.  There aren't many things in C-esqe syntax that work like the increment operator.

    I agree. I'd bring it up as a good lesson for everybody.



    Yah.... I just got pwnd.....Learn something every day!


  • @smbell said:

    @Angstrom said:
    @shadowman said:
    Yup.  At least in c++, that's correct.

    #include <iostream>

    int main() {
        int a = 42;
        a = a++; // whups
       
        std::cout << a << std::endl;
        return 0;
    }


    This displays 42.


    ...on your machine, compiler, and configuration.  The statement marked "whups" has, formally, undefined behaviour.  The program could print 42, 43, 41, format your hard drive, mail nasty pictures of yourself and a goat to your boss, or make demons fly out your nose and still fall within the C++ specification.

    In C/C++ (I'm pretty sure both) this has undefined behaviour, but in Java it's behaviour is specifically ordered. Basically the unary increment operator has a higher precedent than the assignment operator. I've seen it work both ways with various C++ compilers (although I can't remember it ever mailing those pictures to my boss, guess I've been lucky).



    You are confusing operator precedence (not "precedent") with evaluation order.  Operator precedence indicates how "tightly" an operator binds to operands.  People unfamiliar with Lisp get a swift kick in the face when they first try it, because Lisp has NO precedence rules, and parentheses are required for all ambiguous expressions.

    For example, the following statement is actually ambiguous:
                  i = j++;
    It could be interpreted as:
                 (i = (j++));
    or
                 (i=j)++;   // which would be equivalent to i=j; i++;

    Now, in the case of certain screwy constructs, like this:
                a = a++;
                a = (a+=5);
                printf("a is %d, a++ is %d\n", a, a++); // this might not output a true statement!

    C/C++ says the results of these operations are undefined, because the order that the pieces are evaluated in is not guaranteed.    In fact, most compilers will actually evaluate the a++ first to produce more efficient code (because the arguments are evaluated and placed onto the stack in reverse order).
    The only guarantee you have is that, for example:
              if (a || b) { ... }
    Here, 'a' is always evaluated first, and only if it is false is 'b' evaluated. This is so that you can do this sort of thing:

    int *ptr;
    if (ptr==NULL || *ptr == 0)  { ptr_is_null_or_zero(); }

    without worrying that the compiler might try to check *ptr first, and crash if it's NULL.  Visual Basic doesn't have this feature, leading the (already verbose) VB code to require constructs like:
    dim flag as boolean
    flag = (obj is nothing)
    if not flag then flag = (obj.member = 5) ' note the evil dual meaning of =
    if flag then
       ' whee
    end if

    (VB.NET adds AndAlso and OrElse with short-circuit evaluation, but it's still ugly as sin.)

    Anyway, Java *does* have a very specific evaluation order specification. Details here:
    http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html

    Although I must admit, based on the documentation there, it looks like 'x = x++' in Java *should* leave 'x' unincremented.  


  • Oh noes, it's introductory programming coming to get me.

    "For these 50 statements, print the final value of x or describe all errors that would prevent it from executing."

    I must admit that I can no longer, from memory, list all the operators from any language in order of precedence. :(




  • @Angstrom said:

    @shadowman said:
    Yup.  At least in c++, that's correct.

    #include <iostream>

    int main() {
        int a = 42;
        a = a++; // whups
       
        std::cout << a << std::endl;
        return 0;
    }


    This displays 42.


    ...on your machine, compiler, and configuration.  The statement marked "whups" has, formally, undefined behaviour.  The program could print 42, 43, 41, format your hard drive, mail nasty pictures of yourself and a goat to your boss, or make demons fly out your nose and still fall within the C++ specification.


    Hmmm...  Didn't realize that was undefined behavior.  I got 42 with g++ at work, and then tried it at home with VC++ and IT FORMATTED MY HARD DRIVE!!!

    Not really, but I got 43. Whups.

    Though I'd like to see a compiler that did dirty things like that when you invoked undefined behavior :-)



  • @powerlord said:

    @Oliver Klozoff said:
    Although I must admit, based on the documentation there, it looks like 'x = x++' in Java should leave 'x' unincremented.

    It does. Given the following, you get 42 as output.

    public class Test {
    	public static void main(String[] args) {
    		int selected = 42;
    		selected = selected++;
    		System.out.println(selected);
    	}
    }

    P.S. Is there any way to use indentation on this board? For some reason or another, I don't get a rich text editor with Opera.

    I'm not using an RTE with Firefox either.

    There are two methods to get indentation (even though i'm not sure the first one works):

    • First is to use Non Breaking White Spaces, or &nbsp;

    • Second is to use <blockquote><pre>your stuff</pre></blockquote> to wrap your code, e.g.,

      -module(bench).
      -export([generate/1, empty/0, generate2/1, dead/0]).
      

      generate(0) ->
      ok;
      generate(N) when is_integer(N) ->
      spawn(bench, empty, []),
      generate(N-1).

      generate2(0) ->
      ok;
      generate2(N) when is_integer(N) ->
      spawn(bench, dead, []),
      generate2(N-1).

      empty() ->
      receive
      {Pid, Message} ->
      Pid ! Message
      end.

      dead() ->
      ok.



  • @merreborn said:

    Honestly, I'd cut the guy a little slack.  There aren't many things in C-esqe syntax that work like the increment operator.

    What?! This is very basic stuff. I knew this by heart when I was in the 10th grade.

    Perhaps if he wasn't actually brought on to do this kind of work I can understand being easy on him, but if he was hired to program he should be whipped with a cat o' nine tails and then fired.



  • @Oliver Klozoff said:




    In C/C++ (I'm pretty sure both) this has undefined behaviour, but in Java it's behaviour is specifically ordered. Basically the unary increment operator has a higher precedent than the assignment operator. I've seen it work both ways with various C++ compilers.



    You are confusing operator precedence (not "precedent") with evaluation order.  Operator precedence indicates how "tightly" an operator binds to operands.  People unfamiliar with Lisp get a swift kick in the face when they first try it, because Lisp has NO precedence rules, and parentheses are required for all ambiguous expressions.

    For example, the following statement is actually ambiguous:
                  i = j++;
    It could be interpreted as:
                 (i = (j++));
    or
                 (i=j)++;   // which would be equivalent to i=j; i++;

    C/C++ says the results of these operations are undefined, because the order that the pieces are evaluated in is not guaranteed. In fact, most compilers will actually evaluate the a++ first to produce more efficient code.


    Given that increment has higher precedence than assignment, then what could possibly posess any smartass C(++) compiler to evaluate assignment first?


  • @dhromed said:


    Given that increment has higher precedence than assignment, then what could possibly posess any smartass C(++) compiler to evaluate assignment first?

    Performance? When the result of the assignment is required earlier (a likely assumption), the program might save a few CPU cycles when the assignment is made first (due to the mysteries of modern CPUs...)



  • So what you're saying is that the programmer can't rely on the spec of the language, because the CPU/Compiler might say, "Nah. I'm a do it my way, bruv. I don't care if your program bombs. It'll bomb a little faster, no?"

    What's the point of defining operator precedence in languages then?




  • @dhromed said:

    So what you're saying is that the programmer can't rely on the spec of the language, because the CPU/Compiler might say, "Nah. I'm a do it my way, bruv. I don't care if your program bombs. It'll bomb a little faster, no?"

    What's the point of defining operator precedence in languages then?



    No, according the the C/C++ spec that behavior is undefined.  The compilor can do pretty much anything it wants.

    In Java it is defined, and it's a lost operation.  It all depends on what language you're talking about.



  • it's not precendence, it's when the incrementation happens.  take for example:
    int i = 0;
    while (i++ < 5) {
    //do shit
    }

    how many times does that do shit?  5 times, because what happens is it compares i to 5, then it increments.  it's called POST INCREMENTATION for a reason.  if you want it to work the other way there is an operator for it. 

    int i = 0;

    while (++i < 5) {

    //do shit

    }

    PRE-INCREMENTATION will increment and return the incremented value.  Post-incrementation will return the original value and then increment.



  • Probably what happened here was a cut and paste error. He was slapping in code and forgot to change the variable he was assigning to and since it never caused an error it never got fixed.

     



  • [quote user="shadowman"][quote user="Angstrom"][quote user="shadowman"]Yup.  At least in c++, that's correct.

    #include <iostream>

    int main() {
        int a = 42;
        a = a++; // whups
       
        std::cout << a << std::endl;
        return 0;
    }


    This displays 42.
    [/quote]

    ...on your machine, compiler, and configuration.  The statement marked "whups" has, formally, undefined behaviour.  The program could print 42, 43, 41, format your hard drive, mail nasty pictures of yourself and a goat to your boss, or make demons fly out your nose and still fall within the C++ specification.
    [/quote]

    Hmmm...  Didn't realize that was undefined behavior.  I got 42 with g++ at work, and then tried it at home with VC++ and IT FORMATTED MY HARD DRIVE!!!

    Not really, but I got 43. Whups.

    Though I'd like to see a compiler that did dirty things like that when you invoked undefined behavior :-)
    [/quote]


    I'm waiting for someone to patch gcc so it produces an "++?????++ Out of Cheese Error. Redo From Start." message.



  • [quote user="Carnildo"]I'm waiting for someone to patch gcc so it produces an "++?????++ Out of Cheese Error. Redo From Start." message.[/quote]

    Well, it can already produce a warning (I don't know if it catches all occurences, but it does get the one in the OP), so... it's not a patch, but hey. 

    #! /bin/sh
    gcc -Wsequence-point "$@" 2>&1 | sed -e 's/warning: operation on .* may be undefined/++?????++ Out of Cheese Error. Redo From Start./' >&2

    Unless you wanted it at runtime, that's left as an exercise for the reader. :-P  But even that shouldn't be terribly difficult for someone who knows the GCC innards, since the detection code's already there.


Log in to reply