Before we can really explore the Debugger, we need to deliberately create an error condition; that is, we have to write some Lingo that will malfunction when it runs. That’s actually rather hard to do, because the basic errors you might think of making are all tested for by Director itself. It won’t let you make obvious mistakes, in other words, so you need to do something subtle.
Start with a new Director movie and, in frame 1, place a go to the frame script in the script channel. Then use the #field tool in the Tool Palette to make two new #field sprites on the Stage. Name the #field members "num1" and "num2" in the Cast window. Use the Field tab in the Property Inspector (PI) to set their types to editable, and then create a button labeled "Divide".
Now create a new behavior for the Divide button:
on mouseUp me
nFirstNum = value( member("num1").text )
nSecondNum = value( member("num2").text )ALERT "The result was" && string ( nFirstNum / nSecondNum )
END mouseUp
Here’s what this code does:
nFirstNum = value( member("num1").text )
First we get whatever text has been typed into the #field sprite named "num1" in the Cast, and then we try to convert it to a number with the value keyword.
nSecondNum = value( member("num2").text )
Here we’re doing the same thing with the text typed into "num2".
ALERT "The result was" && string ( nFirstNum / nSecondNum )
And finally we divide the two numbers, convert that result to a string so that it will be treated as text once more, and put the result into an ALERT box. (This is a very simple program, of course.)
Now click the Play button and enter 1 for the first number and 0 for the second, and then click your Divide button. You will get a script error saying you cannot divide by zero (which is true; in mathematics division by zero is undefined, or an operation that yields no known result). Don’t click Cancel or Script… though; instead click Debug…. You should get a Debugger window.
There are three panes to this window. In the upper-left corner is the stack of handlers you’ve passed through to arrive at this point. Since the mouseUp handler was the only one used here, that’s the only handler listed.
To the right is a list of all the variables currently in use in this handler. As you can see, the Debugger is showing you the values for nFirstNum and nSecondNum.
Well, that’s a little obvious, but it’s a quick introduction to how you can get a peek into the way your program believes it should be running. There are more effective uses for the Debugger, which we’ll be covering in the very next section.
Stepping Through Code
Sometimes you might not know exactly where something is going wrong, and so you need to deliberately invoke the Debugger to see what’s happening in your program.
For instance, click Director’s Stop button. (Note that when you
do so, everything in the Debugger disappears.) Open a new Movie script
and enter the following:
on DivideNumbers n1, n2
nResult = n1 / n2ALERT "The result was" && string ( nResult )
END DivideNumbers
This, of course, is not very different from the code you
wrote for the Divide button, by which you may infer we are going to
change that script a little and call this handler from the button’s
behavior, passing along the two numbers entered in the #field sprites
as parameters:
on mouseUp me
nFirstNum = value( member("num1").text )
nSecondNum = value( member("num2").text )DivideNumbers( nFirstNum, nSecondNum )
END mouseUp
Now click Play again and enter 1 for the first number and
6 + 3 * ( —2 )
for the second, paying attention to the parentheses. Click Divide. Well, you got the same script error as before, because 6 + 3 * (—2) is zero, again, and since Director calculates mathematical operations when it takes the value of a field, you’re still dividing 1 by 0.
However, you will notice that there are now two names listed in the handler stack in the upper-left pane of the Debugger, the bottommost one being your DivideNumbers handler. As the arrow in the Debugger shows, the place where the program stopped working was with the line
nResult = n1 / n2
inside that handler. And as you can also see, n2 has a value of 0.
Of course, you know already why this is happening; but you can actually step back through your handlers to see where those values came from.
To do that, click the mouseUp handler listed in the upper-left pane of the Debugger window. What happens? Director does two things:
You can also step ahead into the DivideNumbers handler once more, and as you can see from this example, the Debugger lets you roam through the previous handlers that ran before the one that malfunctioned. In this way, you can see not only the place where the actual script error occurred, but also the events leading up to itwhich often will tell you what went wrong, and where.
Okay, click the Stop button again and notice that, once more, the Debugger clears. Then click Play again and enter 1 for the first number as before, but 7 / 3 for the second, and then click Divide.
Now that was probably unexpected. Director told you the result was 0!
Why? Let’s see if we can use the Debugger to find out.
Open your button’s behavior script and click in the gray bar on the left-hand side just under the mouseUp handler. A red dot should appear there.
This is a breakpoint, or place in your Lingo where you are deliberately telling Director that you want it to pause and open the Debugger window. In other words, you want the program to show you at that point what’s going on, so you set a breakpoint to cause that to happen.
Now click Play again and, with 1 for the first number and 7 / 3 for the second, click Divide.
As you can see, the Debugger window becomes active at that point, with the mouseUp script listed in the stack pane in the upper-left and the variable list to the right. Note that me has a value, but that nFirstNum and nSecondNum are defined in the Debugger as <Void>. This simply means that they don’t have any values assigned to them yet.
Note also that there are some green buttons below the stack list that have become active: a downward-pointing arrow with a line above it, another arrow like that but pointing to the lower right, and a third solid arrow pointing straight down.
Left to right, these arrows allow you to
When you do that, you see that the variable nFirstNum receives a value of 1, which is exactly what should happen according to the Lingo you entered.
Then, when you click the step button again, you see that nSecondNum gets a value of 2. Two? That’s not right. Seven divided by three is two and one-third, or 2.333…. So it’s obvious that there’s one thing that needs fixing in our code already.
With the break arrow pointing to the line that reads
DivideNumbers( nFirstNum, nSecondNum )
click the diagonal arrow, which is the Step Into Script arrow.
Once you do that, you’ll see that the Debugger has carried you into the DivideNumbers handleryou’ve jumped into it, following the Lingo in the same order that Director itself follows it. You can see that the handler stack in the upper left now has the DivideNumbers handler listed, and that to the right n1 and n2 are shown with values of 1 and 2, respectively. nResult shows a value of <Void>, which you remember means it just hasn’t been given a value yet.
So now if you click the step button, you see that the division operation takes place, but that nResult’s value is 0, which is strange, because one divided by two is one-half, or 0.5.
Now we’ve found what is happeningour numbers are not working as decimalsbut the larger question of why is still unanswered.
It’s happening because Director defaults to integer math operations when performing many different mathematical functions, which means that while 7 divided by 3 is 2 1/3 (or 2.333…), Director truncates the trailing decimal, giving us an incorrect result of 2.
What’s worse, Director now assumes that this 2 value is meant to be an integer. So when it divides 1 by 2, it assumes the result is supposed to be an integer too, and 0.5 gets truncated to zero.
In order to fix this, we must explicitly tell Director that we want it to perform math calculations with decimals by using the float keyword. This forces Director to work with decimals, even if it would normally work with integers only.
To change things, we need to rewrite some of our code, beginning with the Divide button’s script:
on mouseUp me
fFirstNum = float ( value( member("num1").text ) )
fSecondNum = float ( value( member("num2").text ) )DivideNumbers( fFirstNum, fSecondNum )
END mouseUp
Here you can see we’ve added the keyword float to the value operations we’re getting for our variables. We’ve also changed their prefixes from n to f, to indicate we’re not working with integers any more, but rather floating-point numbers.
Then we need to rework the DivideNumbers handler a little too:
on DivideNumbers f1, f2
fResult = float ( f1 / f2 )ALERT "The result was" && string ( fResult )
END DivideNumbers
Technically, this second float specification is
redundant, since the two variables that have been passed into this
handler are already floating-point numbers. It’s been included here
because it’s not a bad practice, when you’re writing Lingo scripts, to
specify the format you want a given variable to have as Director
manipulates and displays it. After all, as we’ve just learned, if we
don’t do so, unexpected or weird things can happen.
Note too that we’ve changed the n prefixes here to the letter f, just as we did in the mouseUp script, and for the same reasons.
Now does it work? Go back into your mouseUp handler and make sure the breakpoint is still in place, then close the script window and click the Play button. By the time you’re through seeing the value for fSecondNum being set, you’ll see that it seems to be working, so you can simply click the third arrow (the run script arrow) in the Debugger’s window, which will cause the rest of your Lingo to execute. And there you are; you learn that the result of your calculations is 0.5, which is still not what we expected.
Now, 1 divided by 2.333… is not, in fact, 0.5; if you do this in the Message window:
-- Welcome to Director --
put 1.0 / 2.333
You see the result is less than one-half:
-- 0.4286
Run your program again and pay attention to the value given to fSecondNum
as it appears in the Debugger. Though the variable is given a decimal,
the division operation on the equation in the field is being handled before the float keyword, which means that we’re getting the integer value of 7 / 3, or 2.0not the 2.333… we actually want.
Here the Debugger has shown us a fundamental error in the way the program operates, demonstrating that it’s not really our Lingo that is at fault any more, but rather a basic hitch in the way Director handles math. Unfortunately for this one, there is no easy fix, because there’s no simple way to force the text the user enters into floating-point values as it is being entered.