C# code executes instructions under if AND else
Hello guys,
i have the strangest problem i ever had since i am working with Unity. The thing is that in multiple if-else or if-else if-else statements the instructions under if AND else are called and i can see no error or pattern under which this strange and actually impossible thing happens. One example is this:
if (pointerRepresentation.contains(nearestEdgePixel))
{
if (!m_currentSnapPoint.PointerOverElement)
m_currentSnapPoint.OnPointerEnter(m_currentSnapPoint, LeapMotionManager.Instance.Pointer);
} else if (distancePointerToEdge <= m_snapToPointThreshold)
{
if (!m_currentSnapPoint.PointerSnapped)
m_currentSnapPoint.OnPointerSnappingStarted(m_currentSnapPoint, LeapMotionManager.Instance.Pointer, pointedImageViewComponent);
}
else
{
if (!m_currentSnapPoint.InReachOfPointer)
m_currentSnapPoint.OnSnapPointInReach(m_currentSnapPoint, LeapMotionManager.Instance.Pointer, pointedImageViewComponent);
else if (m_currentSnapPoint.PointerOverElement)
m_currentSnapPoint.OnPointerExit(m_currentSnapPoint, LeapMotionManager.Instance.Pointer);
if (m_currentSnapPoint.PointerSnapped)
m_currentSnapPoint.OnPointerSnappingEnded(m_currentSnapPoint, LeapMotionManager.Instance.Pointer, pointedImageViewComponent);
}
Here the codes goes first into the outer if (pointerRepresentation.contains(nearestEdgePixel))
because the pointer contains the nearestEdgePixel and executes all it should but after this he goes into the last outer else, doesn't check if (!m_currentSnapPoint.InReachOfPointer)
and else if (m_currentSnapPoint.PointerOverElement)
but goes instantly into the if (m_currentSnapPoint.PointerSnapped)
instructions even if PointerSnapped is false at this exact moment (i tested it via break points). This and something like this i have in two other if-else statements. Any ideas how this can happen?
Your code is tricky to follow - the lack of comments, the inconsistent use of {} around if/else blocks, and the fact that some conditions are negated means I'm not sure many will be able to help you. However, I can assure you that, as you've already realised, Unity is not executing both branches - there's a flaw in your logic somewhere.
I suggest rewriting your code section by section, commenting clearly when you expect each block to be entered, and testing as you go. Although it'seems not necessary to include {} for single-line if blocks, I strongly recommend you consider it.
I had it commented but somehow the code sample editor messed up the structure with all my comments so i removed them because is thought that maybe the names of the variables could maybe be self-explaining but thank you for your advice :)
I tried to write all, even the single lines, with {} but unfortunately it didn't helped. The only thing which helps is to set a return in every if, else-if or else (which is really not nice) ... then it will execute the code as it should. But even if the else-statement is also true the program shouldn't enter it after it entered the if-statement already since this is forbidden per definition. So it's still really strange ...
The variable names are self-explanatory, but not the logic :) So, in the absence of comments, can you use line numbers as a reference to describe a situation where you believe code execution to have fallen into the wrong block, and the value of the variables used in any tests along the way? $$anonymous$$ake liberal use of Debug.Log if you have to!
Here is an image of my code shown in Visual Studio and i draw a little to show better what happens :)
Answer by tanoshimi · May 11, 2016 at 09:57 AM
I wouldn't become too focussed on whether step-through appears to be skipping lines - that's more indicative of a bug in your debugger rather than a bug in your Unity code.
Let's keep it simple - can you create a situation where Debug.Log() prints out values of variables that differ from those in the condition blocks necessary to reach that line of code? For example, try amending your code like this:
if (pointerRepresentation.contains(nearestEdgePixel))
{
if (!m_currentSnapPoint.PointerOverElement) {
Debug.Log("pointerRepresentation.contains(nearestEdgePixel) should be true and is " + pointerRepresentation.contains(nearestEdgePixel));
Debug.Log("m_currentSnapPoint.PointerOverElement should be false and is " + m_currentSnapPoint.PointerOverElement);
m_currentSnapPoint.OnPointerEnter(m_currentSnapPoint, LeapMotionManager.Instance.Pointer);
}
}
else if (distancePointerToEdge <= m_snapToPointThreshold)
{
if (!m_currentSnapPoint.PointerSnapped) {
Debug.Log("pointerRepresentation.contains(nearestEdgePixel) should be false and is " + pointerRepresentation.contains(nearestEdgePixel));
Debug.Log("distancePointerToEdge should be <= m_snapToPointThreshold. distancePointerToEdge is " + distancePointerToEdge + " and m_snapToPointThreshold is " + m_snapToPointThreshold);
Debug.Log("m_currentSnapPoint.PointerSnapped should be false and is " + m_currentSnapPoint.PointerSnapped);
m_currentSnapPoint.OnPointerSnappingStarted(m_currentSnapPoint, LeapMotionManager.Instance.Pointer, pointedImageViewComponent);
}
}
else
{
if (!m_currentSnapPoint.InReachOfPointer)
Debug.Log("pointerRepresentation.contains(nearestEdgePixel) should be false and is " + pointerRepresentation.contains(nearestEdgePixel));
Debug.Log("distancePointerToEdge should be > m_snapToPointThreshold. distancePointerToEdge is " + distancePointerToEdge + " and m_snapToPointThreshold is " + m_snapToPointThreshold);
Debug.Log("m_currentSnapPoint.InReachOfPointer should be false and is " + m_currentSnapPoint.InReachOfPointer);
m_currentSnapPoint.OnSnapPointInReach(m_currentSnapPoint, LeapMotionManager.Instance.Pointer, pointedImageViewComponent);
else if (m_currentSnapPoint.PointerOverElement)
Debug.Log("pointerRepresentation.contains(nearestEdgePixel) should be false and is " + pointerRepresentation.contains(nearestEdgePixel));
Debug.Log("distancePointerToEdge should be > m_snapToPointThreshold. distancePointerToEdge is " + distancePointerToEdge + " and m_snapToPointThreshold is " + m_snapToPointThreshold);
Debug.Log("m_currentSnapPoint.InReachOfPointer should be true and is " + m_currentSnapPoint.InReachOfPointer);
Debug.Log("m_currentSnapPoint.PointerOverElement should be true and is " +m_currentSnapPoint.PointerOverElement);
m_currentSnapPoint.OnPointerExit(m_currentSnapPoint, LeapMotionManager.Instance.Pointer);
if (m_currentSnapPoint.PointerSnapped)
Debug.Log("pointerRepresentation.contains(nearestEdgePixel) should be false and is " + pointerRepresentation.contains(nearestEdgePixel));
Debug.Log("distancePointerToEdge should be > m_snapToPointThreshold. distancePointerToEdge is " + distancePointerToEdge + " and m_snapToPointThreshold is " + m_snapToPointThreshold);
Debug.Log("m_currentSnapPoint.PointerSnapped should be true and is " + m_currentSnapPoint.PointerSnapped);
m_currentSnapPoint.OnPointerSnappingEnded(m_currentSnapPoint, LeapMotionManager.Instance.Pointer, pointedImageViewComponent);
}
That's how I interpret the conditions for each block, but you might want to check them carefully! Can you make this code print out a seeming anomaly?
Okay i tried this and while the bugger still shows this weird thing the output of the Debug.Log() doesn't ... and somehow the bug to which this had led is also gone ... i have no idea how ... and it is really possible that the debugger has such bugs? That's really mean if you can't even trust the debugger! ^^
Well just use "step into" ins$$anonymous$$d of "step over". The problem is that your code is not what is actually executing but the compiled binary byte code which again is compiled to machine code is what is actually executed. Not every instruction can be mapped perfectly to a line of source code.
$$anonymous$$eep in $$anonymous$$d that curly brackets don't have any generated code. They are just for logical grouping during compile time. The actual compiled code doesn't have something like brackets. if statements are actually conditional jumps so the programcounter simply jumps to another chunk of code. At the end of each chunk there's usually an unconditional jump which jumps to a common point. This is the point after all your if / elseif madness. If the pc reaches that point it doesn't know how it get there. Since several code blocks finally lead to the same point (where you ultimatively leave the current method) the debugger has to put your current line "somewhere" after that jump. Again brackets are not code so the current line is usually never at a line with just a curly bracket
The point you marked as "step2" is most likely the meeting point of all code chunks within the outer if statement. However you only see "the line", but not if you're going to execute that line or if you're finished. It most likely is actually behind that line of code (or to be more precise behind the opcode sequence that represents that line of code).
When you do a "step into" ins$$anonymous$$d of a "step over", you actually enter the method that might be called in the current line of code. If it doesn't actually jump into that method, it's not executed. But as @tanoshimi said, to verify which parts are executed you should use Debug.Log. A debugger is mainly used to track the change of data / state during execution.
if statements work as specified by the language. Those are fundamental rules. If you couldn't trust them program$$anonymous$$g would be pointless ^^.