3

Here is one of my self-study homework problems.

I am supposed to write down the output of this program without actually running it. I understand all the syntax and the variable-passing here, (and I have the answers) but for some reason, tracing it out on paper isn't working.

Is there some secret diagramming technique that keeps everything organized?

Is figuring this out by hand mere child's play to an experienced programmer?

Thanks

public class Mystery extends ConsoleProgram {
public void run() {
    ghost(13);
}

private void ghost(int x) {
    int y = 0;
    for (int i = 1; i < x; i *= 2) {
        y = witch(y, skeleton(x, i));
    }
    println("ghost: x = " + x + ", y = " + y);
}

private int witch(int x, int y) {
    x = 10 * x + y;
    println("witch: x = " + x + ", y = " + y);
    return x;
}

private int skeleton(int x, int y) {
    return x / y % 2;
}
}
user229044
  • 232,980
  • 40
  • 330
  • 338
dwilbank
  • 2,470
  • 2
  • 26
  • 37
  • 3
    I'm sure I could figure it out but, as an experienced programmer, I write unit tests and change the code till it passes. It's not like there's something wrong with you if you find this chunk of code confusing, it seems intended for confusion. – JoshRagem Aug 05 '12 at 05:09
  • I'd argue that the only confusing thing is the value of `y`, which, if you're an experienced programmer, isn't what it seems on the first (few) pass(es). – Makoto Aug 05 '12 at 05:13

5 Answers5

3

Try writing down a stack of method calls with the number that's been passed in, example:

run()
ghost(13)
skeleton(13,1)

etc.

At each method call, find some scratch space and write out the variables and try to work out what the code does until you get a return value. Then take that return value and go back to the last point in that method stack and scratch that method off.

For example, the top (bottom) of the above example stack is skeleton(13,1), so you try to work out what skeleton() returns when x is 13 and y is 1. Easy enough, it's 1. Then go back to the stack and see what that return value should go. In this case it's witch(), so the stack is:

run()
ghost(13)
witch(0,1)

and continue until run() is finished.

Jon Lin
  • 142,182
  • 29
  • 220
  • 220
3

Usually I use table that have 2 column(Memory and Monitor) Like this:

====================
| Memory | Monitor |
====================
|        |         |
|        |         |
|        |         |
|        |         |
====================

Memory is like watch in debug. Monitor is what will output in monitor

So for example:

int x; // Declare X (Memory)
x=10; // fill with 10 (Memory)
System.out.println(x); // print it (Monitor)

If i trace use that table:

====================
| Memory | Monitor |
====================
| x=10   | 10      |
|        |         |
|        |         |
|        |         |
====================

I hope this will help you

UPDATE: I want to explain more detail:

Let's take a look with code that i created before

1. int x; // Declare X (Memory)
2. x=10; // fill with 10 (Memory)
3. System.out.println(x); // print it (Monitor)

Step 1: I declare X. So the table look like this:

====================
| Memory | Monitor |
====================
| x      |         |
|        |         |
|        |         |
|        |         |
====================

Step 2: I fill x with 10 then look like this:

====================
| Memory | Monitor |
====================
| x=10   |         |
|        |         |
|        |         |
|        |         |
====================

Step 3: I print x

====================
| Memory | Monitor |
====================
| x=10   | 10      |
|        |         |
|        |         |
|        |         |
====================
Kenjiro
  • 749
  • 1
  • 12
  • 33
2

What you can do is to actually emulate every scope (think method) on a sheet of paper, where you write down all the variables.

If you call a method you take a new piece of paper and put it on the stack of existing paper. If you return from a method you throw the top most piece a way. If you have classes you would need a separate sheet for those.

That is what you could do. But no real programmer does that.

What you do instead is:

  • understand the basic structure from looking at the code. Things like: It will call "witch" a couple of time before it will print "ghost".

  • for understanding the details you guide and double check your thoughts with logging/system out statements and / or the debugger and actually executing the code.

So is the exercise useless? Don't think so. While you don't do it on its own it is part of thinking about code and you do that all the time one way or the other.

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
  • This is a good method, except instead of using entire pieces of paper, just represent new pages with a box on the same sheet, when you leave the method simply cross the box off and update the calling method's variables. – Brandon Aug 05 '12 at 05:13
0

Since run() is the only method that is visible to main() (and thus capable of being called), you would only need to perform variable-to-value substitution. Place the value of the variables in as they come along and are generated.

It isn't hard once you get the hang of substituting variable values, which is an invaluable debugging tactic.

Makoto
  • 104,088
  • 27
  • 192
  • 230
0

You can unroll loops:

for (int i = 1; i < 13; i *= 2) {
    E[i]
}

becomes

E[1]; E[2]; E[4]; E[8];

There's no recursion here, so the rest should be straightforward.

Judge Mental
  • 5,209
  • 17
  • 22
  • thank you sirs - I'm trudging through it one more time. I like the idea of plugging it into a compiler and fiddling with it till it works right. – dwilbank Aug 05 '12 at 05:16
  • Got it! And I hope I never have to do one of these again. – dwilbank Aug 05 '12 at 05:37