Hacker News new | ask | show | jobs
by chasd00 41 days ago
Genuinely curious, so this is undefined behavior and depends on the compiler. I get that. Java, and other languages, can do these same operations but their compilers produce bytecode that runs on a virtual machine (JVM) compiled to machine code just-in-time. Would this same code in Java possibly yield different results based on the platform the JVM was running on because of the platform specific JIT compiler? Maybe that's part of the origin of the phrase "write once, test everywhere".
4 comments

The UB comes from how C++ standard defines expression sequencing which is not relevant for Java. Languages other than C++ typically define such details more strictly so there is no UB or even concept of UB. JIT compilers don't change it as any non toy JIT will generate native instructions directly or through intermediate representation (instead of generating C++ text and passing that through regular C++ compiler) both of which should have much stricter semantics compared to what C++ guarantees.
late to this but what i meant was the JIT Compiler had to be compiled by a compiler at some point so its behavior is defined by the compiler used to compile it (this goes all the way down to the poor soul who hand compiled the first compiler). I'm assuming things like JIT are platform dependent and therefore the compiler used to build it would also be platform dependent. So the JIT on different platforms could have been built from different compilers choosing their own way of handling undefined behavior. ...unless i'm confusing myself which is likely.
The compiler is compiled via java nowadays. It's bootstrapped.

Yes the first one was probably written in C, however long ago. Not super relevant now though.

JVM/JRE, probably a different story

> Would this same code in Java possibly yield different results based on the platform the JVM was running on because of the platform specific JIT compiler?

No, and it's also well defined in languages like C#.

If we're talking about this specific example at least. No sequence point issues like that in Java.

I'd be badly surprised if the jvm jit went through C, so if this monstrosity is well defined in Java it's well defined once well defined everywhere.

but still, if it were, it was and remained, as gp points out, bad practice...

It's been quite a while, but IIRC, in Java these statements actually do have a defined behavior.

The ++x is a "pre-increment", meaning the value of the variable is incremented prior to evaluating the expression, while the "post-increment" "x++" is the other way around: the expression evaluates to x, then x is incremented afterwards.

All expressions are left-to-right.

That behavior is inherited from C. The pre/post increment behavior is actually the same in every language that uses them. The priority of operation is also usually the same as well.

The reason the question is tricky is because those operators change the value of a as the full expression is progressively executed.

It's not immediately clear to me what the answer in Java would be.

Just take a++ + ++a for example:

If the value if `a` is hoisted by the jvm then it could be 5++ + ++5, so 5 + 6.

But if it's executed left to right and `a` is looked up every time, then it becomes 5++ + ++6, so 5 + 7.

The value of the variable is not hoisted by the Java compiler. (It's not that JVM, that only executes the byte code, what y doesn't have that kind of ambiguities.)

The semantics of Java is not undefined on multiple assignments to the same variable in an expression, so it can't hoist something if it would change the outcome.

Now, I don't actually know what the outcome is, because I don't remember whether `a += e` reads the value of `a` before or after evaluating `e`. The code is still confusing and unreadable to humans, so you shouldn't write it, but the compiler behavior is not undefined.

And if your variable is accessed from multiple threads, it may be undefined which intermediate values night be seen.

    $ cat a.java 
    class a {
        public static void main (String[] args) {
            int a = 4;
            int b = a++ + ++a;
            System.out.println(b);
            System.out.println(a);
        }
    }

    $ javac a.java 
    $ java a
    10
    6