4

I have this very simple piece of code in java:

anyMoreDelayedExplosion |= performEffect(getPanelMap(), getGameState(), this, x, y, effect, true);

anyMoreDelayedExplosion is a boolean field of the class that contains this statement. performEffect is a static method that returns either true or false.

Now, I debugged this (with Android-studio debugger), and I made sure that before executing the =| operation, anyMoreDelayedExplosion is "true". Then, after the operation, it becomes "false".

If I change the code to:

boolean res = performEffect(getPanelMap(), getGameState(), this, x, y, effect, true);
anyMoreDelayedExplosion |= res;

And check again, it correctly stays "true".

How is this possible?

My guesses:

  1. The debugger is not reliable. Still, this results in an evident bug in the application, that unbelievably gets FIXED by the above correction.
  2. There is an optimization issue of some kind with the compiler.
  3. I am totally, completely and utterly missing some truth here.

If anyone has any guess or ideas about how to isolate this kind of behavior, I would be happy to hear them out. Thanks.

EDIT: Here are the declarations, for type completeness:

boolean anyMoreDelayedExplosion;
public static boolean performEffect(PanelMap pm, GameState state, GameSceneHittable scene, int x, int y, SpecialEffect effect, boolean playFX)
Lake
  • 4,072
  • 26
  • 36
  • 3
    Does `performEffect` do anything that could modify `anyMoreDelayedExplosion` of this object, or of any object of the class? I still can't see how this could make a difference... – ajb Dec 10 '14 at 05:32
  • are you sure that performEffect() is returning a boolean? – codeMan Dec 10 '14 at 05:33
  • @codeMan There's no other way the code could compile, as far as I know. – ajb Dec 10 '14 at 05:33
  • 1
    Is there multithreading going on here? – Andrew Janke Dec 10 '14 at 05:34
  • No multithreading what-so-ever, and that code compiles perfectly it seems. Also yes, performEffect might modify anyModeDelayedExplosion, but it should not make a difference. Also updated with declarations. Thanks for you effort guys. – Lake Dec 10 '14 at 05:35
  • Just FYI - If the anyMoreDelayedExplosion is class variable and if you are not initializing it, it will be initialized to false by default. – codeMan Dec 10 '14 at 05:37
  • I think performEffect() is changing the value of anyMoreDelayedExplosion variable, I am only guessing it by seeing that you are passing THIS as a parameter to the performEffect() – codeMan Dec 10 '14 at 05:41
  • Strange. Maybe time to start eliminating alternatives... what happens if you observe `anyMoreDelayedExplosion` immediately before the call using a printf() or logging output? Since you're passing `this` in the call, I'd guess that `anyMoreDelayedExplosion` is getting twiddled inside the `performEffect()` call, and maybe that is interacting with the debugger, or some other program state that isn't adequately accounted for in the debugger-vs-no-debugger test setup. – Andrew Janke Dec 10 '14 at 05:44
  • Actually, I take that back. The JLS says that for `|=`, the value of the LHS is saved before the RHS is evaluated, so changes to `anyMoreDelayedExplosion` inside the called method should be ignored. http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.26.2 – Andrew Janke Dec 10 '14 at 05:47
  • @Andwer Janke Actually, I am stepping inside the performEffect, going through it ALL with the debugger, and when it returns, anyMoreDelayedExplosion is "true" (as it should be), also that actually becomes a bug in the application that is, to my suprise, 100% fixed by the above correction.... – Lake Dec 10 '14 at 05:47
  • @Andwer Janke By the way, there is no "anyMoreDelayedExplosion = false" code anywhere in the code.. Every assignment of that variable is |= – Lake Dec 10 '14 at 05:49
  • Here's my new theory: `anyMore` is actually `false` at the time of the original method invocation, it gets set to `true` via a side effect inside `performEffect`, you're observing it in the debugger *after* that side effect happens but before assignment, and `|=` is using the old stored `false` value when it does the combination. Splitting them in to two lines causes it to evaluate the LHS using its state *after* `performEffect` has run (and set `anyMore` to true) but before the assignment takes place. – Andrew Janke Dec 10 '14 at 05:49
  • (And I guess that would only happen the first time when `anyMore` starts out as false before any assignments.) – Andrew Janke Dec 10 '14 at 05:50
  • Man, you have a really, really deep point here. – Lake Dec 10 '14 at 05:51
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/66536/discussion-between-andrew-janke-and-lake). – Andrew Janke Dec 10 '14 at 05:52

3 Answers3

4

It's an issue with side effects inside the method you're calling interacting with when you observe the field and when the |= operator "observes" the field.

In Java, the compound assignment operators like |= store the value of the left hand side of the expression before evaluating the right hand side. So, if the method called in the RHS of the expression alter the value of anyMoreDelayedExplosion, and they might, since you're passing this to it, those changes will not affect the result of the |= operation. And if you're observing that field value in the debugger after the side effect takes place, what you're seeing as the field is not what was used for the LHS input of the |= operation.

So in this case, anyMore is actually false at the time of the original method invocation, it gets set to true via a side effect inside performEffect, you're observing it in the debugger after that side effect happens but before assignment, and |= is using the old stored false value when it does the combination. Splitting them in to two lines causes it to evaluate the LHS using its state after performEffect has run (and set anyMore to true by side-effect) but before the assignment takes place.

You need to make sure to observe the state of anyMoreDelayedExplosion before the performEffect method is called at all, not just before it returns, for your view to be consistent with what the code is actually doing. Adding a logging or printf statement just before the call would be a good way to do this, or just being careful about when you look at that field value in the debugger.

Section 15.26.2 of the JLS describes the compound assignment operator behavior in detail: http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.26.2

Andrew Janke
  • 23,508
  • 5
  • 56
  • 85
1

First things first, a pragmatic approach is probably the best.

If you have a workaround for the problem, use it. It's a worry that it happened in the first place but there should be two parallel streams happening here.

The first is to deliver your code. If the workaround works (and it does, otherwise it's not a workaround), keep it in your code (with a comment) so that you can continue.


The other stream is investigative in nature. What you describe should not be happening, sans some external forces like threading or debugger issue as you posit, or the function itself changing the flag as a side-effect of its operation.

Your best bet is to narrow it down to the bare minimum of code that has the problem, and ship that off to Google for analysis (or post the complete sample here so we can do a proper analysis rather than (educated) guesswork).

If you want to continue investigating the problem rather than shipping it off to those who might be in a better position, I'd start by single-stepping into the performEffect() method to see what it does in detail. It may be that it's setting the boolean value itself or returning false under some circumstances. If that doesn't reveal anything, investigation of the byte-code would be my next option.

But, that's getting deep into something that you really shouldn't be worried about, especially if there's a viable workaround.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • Does that operator really exist? I must be drunk probably but I fail to find it anywhere, and it fails to compile. Do I have to write it unrolled? I mean, I don't understand why the bitwise operation should screw things up here (it's java) – Lake Dec 10 '14 at 05:15
  • This is incorrect. `|` is the non-lazy boolean OR operator (as well as the bitwise OR operator). And `||=` does not exist. – user253751 Dec 10 '14 at 05:16
  • Great, I really thought I was going nuts. That puts me back to the original question.. – Lake Dec 10 '14 at 05:17
  • @paxdiablo Thanks for your answer. Do you have a guess for what exactly would be happening when I use the bitwise operator, and why that screws up things at runtime? – Lake Dec 10 '14 at 05:18
  • http://stackoverflow.com/questions/1724205/effect-of-a-bitwise-operator-on-a-boolean-in-java According to this, |= is a LOGICAL OPERATOR when used between booleans. Is that wrong? – Lake Dec 10 '14 at 05:21
  • 1
    @paxdiablo Nothing in Java can be "forced" into a boolean, except for `Boolean` which is unboxed. If `performEffect` doesn't return a `boolean` or `Boolean`, the compiler will reject it. – ajb Dec 10 '14 at 05:27
  • From the java specs: http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.22.2 – Lake Dec 10 '14 at 05:32
  • By the way, it's not necessarily true that the OP "should" be using the form with `||`. You don't know what he's trying to do. `x |= y` always evaluates `y`, and `x = x || y` doesn't always. If he wants to evaluate `y` in all cases, then he doesn't want to use `||`. It's uncommon, but I've seen code like this where the right-hand operand should always be evaluated. – ajb Dec 10 '14 at 05:36
  • @ajb That is exactly the point, I want the method to be called no matter what. – Lake Dec 10 '14 at 05:40
  • @paxdiablo This is java, so if the operands are not boolean I should have a "compile error" instead of "weird effect", hence my surprise and question. – Lake Dec 10 '14 at 05:41
0

There's no logical explanation for the behavior you're describing. Surely the runtime behavior is correct, regardless of what you're seeing in the debugger.

If you've declared the variable anyMoreDelayedExplosion outside an outer loop where it's repeatedly initialized and then or-equaled in an inner loop for different scenarios, I suppose it's possible you could be seeing the value after it's been re-initialized to false. But it sounds like you know what you're doing better than to be confused by such.

gknicker
  • 5,509
  • 2
  • 25
  • 41
  • Thanks.. actually, it's worse than that: anyMoreDelayedExplosion is a field of that class, and there are only statements that makes it "true" (it starts by "false"). With the debugger, I make sure that it becomes "true", then I do a series of "step over" and it remains true up until that precise point of the question. THERE it changes value. I really, really don't understand this. – Lake Dec 10 '14 at 05:38
  • @Lake, if you're stepping over the static function call, you may be missing it changing the variable behind your back. I'd suggest stepping into that function, keeping a watch on the variable. – paxdiablo Dec 10 '14 at 05:48
  • @gknicker As incredible as it seems, there actually is a logical explaination. See Andrew's answer. – Lake Dec 10 '14 at 06:10