I don't know that compilers *aren't* allowed to evaluate operands in whatever order they want; maybe A && B doesn't get evaluated in that order.
Excellent guess! Yes, in fact modern compilers are prone to rewriting code routinely if they have reason to believe that doesn't affect the semantics. And then the JVM does the same thing based on its runtime data. Moreover, modern *chips* are prone to doing the same thing with the compiled code, rewriting the assembly to squeeze out a few microseconds here and there.
This is part of what makes multi-threaded code fiendishly difficult and fraught: there are things you can do that *look* completely sound, but allow the microcode to perform rewrites that make perfectly good sense from a single-threaded perspective, but totally break the semantics when multiple threads are interacting. Worse, these bugs are *incredibly* difficult to find and debug, because they will often arise only once in a million runs. So building multi-threaded code correctly is *weirdly* complicated, involving more contortions than you would expect at first glance.
And this, in turn, is one of the beauties of the Futures approach -- it isn't nearly as susceptible to those bugs as traditional lock-based approaches.
(no subject)
Date: 2019-05-09 02:21 am (UTC)Excellent guess! Yes, in fact modern compilers are prone to rewriting code routinely if they have reason to believe that doesn't affect the semantics. And then the JVM does the same thing based on its runtime data. Moreover, modern *chips* are prone to doing the same thing with the compiled code, rewriting the assembly to squeeze out a few microseconds here and there.
This is part of what makes multi-threaded code fiendishly difficult and fraught: there are things you can do that *look* completely sound, but allow the microcode to perform rewrites that make perfectly good sense from a single-threaded perspective, but totally break the semantics when multiple threads are interacting. Worse, these bugs are *incredibly* difficult to find and debug, because they will often arise only once in a million runs. So building multi-threaded code correctly is *weirdly* complicated, involving more contortions than you would expect at first glance.
And this, in turn, is one of the beauties of the Futures approach -- it isn't nearly as susceptible to those bugs as traditional lock-based approaches.