strange problem can't debug

EDIT: code is posted
HERE

Project can be imported into eclipse from the war attached to this post.


In my app i have a bunch of buttons with numbers on them.
Above and below are smaller buttons that increment and decrement the middle buttons showing the numbers.
I made it so, that if you increment a number, and if it finds that the number exists already, it jumps over, so if there’s two numbers, 14 and 15 and you increment the first, it automatically jumps to 16.


The problem is, that it only works if the column beeing incremented is to the left of the column it’s going to jump over, if it’s to the right of the pivot number it’s got to jump over, it jumps twice, meaning take two numbers for instance, 15 and 14, incrementing 14 will jump it to 17, because it’s to the right of the other, this is a general rule in this app (bug).

While debugging the bug, the flow jumps all of a sudden out of the method doing the calculations, making it repeat, which makes it increment/decrement twice, causing the bug. Need some help with this one, can’t tell why it is happening. I’m not using threads myself… might be an extra request is made somehow, doing this.

The test.war contains the sources, can be easily imported in Eclipse as a project, and deployed on Tomcat.

To get the numbers click New Prognosis > Hybrid then click Generate.

11312.png
11313.war (3.41 MB)

Hi,

I just quickly glanced at the code, so there is a chance I read your algorithm wrong, but it seems that the recursive call to
getNextValid()
will increment the number, then the ‘outer’ loop will hit it again, incrementing once more.
A
break
after the recursive
getNextValid()
might do it, though I did not give this much thought…

Regarding jumping out of the loop while debugging: if you place the breakpoint within the getNextValid() -method, it will seem to jump when you recurse, since it will hit the breakpoint again while recursing. Not sure if this is what’s causing your problem.

Best Regards,
Marc

BTW You’re more likely to get a response if you also include the problematic code straight in the forum post - deploying an ‘unknown’ war from the forum, and then trying to figure out where to find the code that’s causing the problem, is probably not going to get people jumping at the problem :wink:
(That is: nothing wrong with including the war, but some code in addition would be nice)

I always knew which
code
would seem
that “misteriously doesn’t work”, but it does
, as debugging and logic shows,
i’ll post it below
. I gave the war, because i did myself debug line by line and i been baffled… it’s easiest to load the project in eclipse / deploy and see for yourself. If someone doesn’t know by change, is as easy as right click in eclipse’s project explorer, import > war (includes the sources).

When i stepped with debug, left decrement / increment, right pivot, everything is fine, it’s the other way around that missbehaves. Columns in question can be farther apart; no need for pivot number to be adjancent to the one doing the increasing / decreasing.

the class is
view.ui.ExtractionHorizontalLayout
,
the increment / decrement listeners are:
DecrementButtonsClickListener, IncrementButtonsClickListener

and the code that does the work is in
getNextValid

Logic:

It doesn’t make sense that it doesn’t work according to its logic because: if a column to the left of the pivot number makes the jumping over, it works, if a column to the right of the pivot number makes the jumping over, it does twice.

Example:
If 1st column is 25, 2nd is 26, 1st is to the left of 2nd, so it will work, and it does:
it wil go increment to 27 and decrement back to 25

If 1st column is 26, 2nd is 25, 2nd is to the right of 1st, it will not work when it hits pivot “25”, as goes:
it will increment to 28, and decrement to 24, if it hits pivot “26”

Data:


List<Integer> nrs = new ArrayList<Integer>(); //filled in generateButtonListener first in generateGLayout method
	List<NativeButton> nrButtons = new ArrayList<NativeButton>();
	List<NativeButton> decrementNrs = new ArrayList<NativeButton>();

Listener gets triggered:

if (nativeButton == decrementNrs.get(0)){
				getNextValid(nrs.get(0) - 1, 0);
				nrButtons.get(0).setCaption(nrs.get(0).toString());						
			} else if (nativeButton == decrementNrs.get(1)) {
				getNextValid(nrs.get(1) - 1, 1);
				nrButtons.get(1).setCaption(nrs.get(1).toString());
			}

[…]
up to 6 tests, once for each number button.

getNextValid:

/**
	 * Determine if is incrementing by: if (param:nrs(index)-1 > nrs(index)) <br />
	 * If in [1, 49]
 <br />
	 * ____and like another in the extraction <br />
	 * ________do ++ / -- according to $increasing boolean variable <br />
	 * ________recursively repeat method <br />
	 * If in [1, 49]
 (and not like another in nrs) save in nrs using index
	 * 
	 * @param i
	 *            the number
	 * @param index
	 *            index of the extraction list
	 */
	private void getNextValid(Integer i, Integer index) {
		boolean increasing = false;
		if (i > nrs.get(index))
			increasing = true;
[color=#F80000]
\\ for the bug, after exiting the method, it re-enters right here,
\\ the breakpoint is on the method, so it has to pass through the above if anyway,
\\ is this some sort of auto optimization or WTH?
[/color]  :O
		if (i < 50 && i > 0) {
			for (Integer integer : nrs) {
				if (i == integer) {
					if (increasing)
						i++;
					else
						i--;
					getNextValid(i, index);
				}
			}
			if (i < 50 && i > 0)
				nrs.set(index, i);
		}
	}

Debugging follow-up. Simply when the bug occurs, what happends is, after the code exits getNextValid, it jumps immediately in the middle of the method again :open_mouth: at the line i’m marking in red below:

private void getNextValid(Integer i, Integer index) {
		boolean increasing = false;
		if (i > nrs.get(index))
			increasing = true;
[color=#F80000]
\\ for the bug, after exiting the method, it re-enters right here,
\\ the breakpoint is on the method, so it has to pass through the above if anyway,
\\ is this some sort of auto optimization or WTH?
[/color]  :O
		if (i < 50 && i > 0) {
			for (Integer integer : nrs) {
				if (i == integer) {
					if (increasing)
						i++;
					else
						i--;
					getNextValid(i, index);
				}
			}
			if (i < 50 && i > 0)
				nrs.set(index, i);
		}
	}

Yes, the algorithm, as I read it, would cause this - as I said in the first response:

Did you try adding the break?

Edit: I did, and that seems to fix it. Please read and try suggestions :wink:
No, seriously though: this might very well introduce new bugs, but illustrates what the problem is.

Best Regards,
Marc

I added breakpoints as i indicate below with the red lines, they don’t get hit, but they should, and i don’t know what this means because when stepping line by line (F6), it goes through there if i breakpoint the method. Again it works perfectly fine if the number beeing increased is to the left of the one beeing found, that’s the baffling bit (although the breakpoints don’t get hit anyway :O).

						i--;
[color=#FD0000]
					getNextValid(i, index);
[/color]
				}
			}
[color=#FD0000]
			if (i < 50 && i > 0)
[/color]
				nrs.set(index, i);
		}

EDIT: i did read, though beeing the author, is harder for me to see the problem, since i’m stuck in my logic loop :grin:
I need it spelled out for me…-_-

This is what I’m talking about:

    private void getNextValid(Integer i, Integer index) {
        boolean increasing = false;
        if (i > nrs.get(index))
            increasing = true;

        if (i < 50 && i > 0) {
            for (Integer integer : nrs) {
                if (i == integer) {
                    if (increasing)
                        i++;
                    else
                        i--;
                    getNextValid(i, index);
                    [color=#FF0303]
if (increasing)
                        break;
[/color]
                }
            }
            if (i < 50 && i > 0)
                nrs.set(index, i);
        }

    }

Still might introduce bugs, I did not give it a whole lot of thought, but it should show clearly where the bug lies.

Best Regards,
Marc

Yes, it does work (adding just a break after recursion), thank you.
I still can’t see why it was missfiring… very annoying.

If you don’t mind i’ll put the “mark as answered later”, to attract some explanations maybe.

EDIT: for starters those breakpoints don’t get hit because the debugger can’t cope with recursion me think

I made a pass through the method with my mind (where is the logic false please).

This is what i came up with (
still no explanation
)


EDIT: got explanation below, will come up with solution when i got the time.

take 8 (index 0) and 9 (index 1) in the nrs list, while decrementing 9

getNextValid, gets passed value 8 (nrs(1) - 1) and index 1
it passes “is incrementing?” with false
it iterates through nrs finding out 8 already exists at index 0, so it decrements once becoming 7 and it jumps recursively to find out if there are any more 7s

recursive call passes “is incrementing?” with false
it finds out there’s no other 7 in the nrs, so it exists the loop naturally and sets 7 on index 1

after returning from recursion, i variable is still 7, and from that point it sets 7 on index 1 again, no problem there

[color=#FD0000]

EXIT! logically, a break after the recursion would be an optimisation, not a fix, so
what was the problem again w/o the break?
[/color]



EDIT: i think i caught on, after returning from the recursion, because i’m iterating through the nrs, wich now contains 7, it meets with 7 from the i (although it shouldn’t), so it does the recursion again, decrementing once again too (it’s because the for loop doesn’t get the chance to get to the next integer in the list because the recursion returns before it does, or it starts over again which is shouldn’t). The break does stop that from happening, but also opens a new bug, that in which if there’s 7,8,9 and i’m decrementing 9, it will jump over 8 but stop at 7, ending up in 7, 8, 7.

I think i need to come up with a custom loop, no more iterating nicely…

Thank you Marc. The problem needed a pen and paper, but it finally imposed this solution:

/**
	 * Saves the next valid number in the extraction number list.
	 */
	private void getNextValid(Integer next, Integer index){
		boolean increasing = false;
		// Determines if it's increasing by comparing i > nrs(index)-i
		if (next > nrs.get(index))
			increasing = true;
		next = getNextValidWorker(next, increasing);
		if (next < 50 && next > 0) {
			nrs.set(index, next);
		}
	}

	private Integer getNextValidWorker(Integer i, boolean increasing) {		
		if (i < 50 && i > 0) {		
			for(Integer nr: nrs) {
				// if like another in the extraction
				if(nr == i) {
					// get next probable valid number
					if (increasing)
						i++;
					else
						i--;
					
					// recurse to check new number validity
					i = getNextValidWorker(i, increasing);
				}
			}
		} 
		return i;
	}