Beeping Button Brouhaha

Third Problem

We rebuild, download, and rerun. We write the number "2" and tap "Beep". We get the following error in the Inspector:

Expected an integer, got nil
evt.ex.fr.type;type.ref.frame
-48406
(#6008D229).buttonClickScript(), 27: PushConstant NIL
Entering break loop: level 1
We're still in our buttonClickScript, about to execute the code at program counter 27. Here's the NewtonScript code for the buttonClickScript:

func()
begin
   local beeps := StringToNumber(numBeeps.text);
   for i := 1 to beeps do
      :SysBeep();
end
Let's look at the disassembled code for the buttonClickScript:

Disasm(GetCurrentFunction(0))
    0: FindVar              numBeeps
    1: Push                 'text
    2: GetPath              1
    3: Push                 'StringToNumber
    4: Call                 1
    5: SetVar               beeps
    6: PushConstant         1
    7: SetVar               i
    8: GetVar               beeps
    9: SetVar               i|limit
   10: PushConstant         1
   11: SetVar               i|incr
   12: GetVar               i|incr
   13: GetVar               i
   14: Branch               23
   17: PushSelf
   18: Push                 'SysBeep
   19: Send                 0
   20: Pop
   21: GetVar               i|incr
   22: IncrVar              i
   23: GetVar               i|limit
   24: BranchIfLoopNotDone  17
   27: PushConstant         NIL
   28: Return
#2        NIL
We're about to execute the code at offset 27--it looks as though we're at the end of the loop. Let's look at the values of our variables to see if they are reasonable:

GetAllNamedVars(0);
#4419641  {beeps: NIL, 
           i: 1, 
           i|limit: NIL, 
           i|incr: 1, 
           numBeeps: {_parent: {#4418345}, 
                      _proto: {#6008D5D9}, 
                      viewCObject: 0x110A57D, 
                      entryLine: {#44186F5}, 
                      labelLine: {#44181FD}, 
                      width: 73, 
                      indent: 75, 
                      height: 13}, 
           text: "Beep", 
           SysBeep: <function, 0 arg(s) #350E8D>}
It doesn't seem right that beeps is nil. In fact, that would explain the error we got. The for loop expected an integer, but got nil. But why is beeps nil? It was obtained from calling StringToNumber on numBeeps.text. Let's start by looking at numBeeps more closely:

numBeeps := GetNamedVar(0, 'numBeeps);
#4417EA9  {_parent: {_parent: {#4411D11}, 
                     _proto: {#6008D0C1}, 
                     viewCObject: 0x110A483, 
                     numBeeps: <2>, 
                     viewclipper: 17863765, 
                     base: <1>, 
                     viewFlags: 577}, 
           _proto: {viewBounds: {#6008D689}, 
                    label: "Num Beeps:", 
                    entryFlags: 10753, 
                    _proto: {@189}, 
                    debug: "numBeeps", 
                    preAllocatedContext: numBeeps}, 
           viewCObject: 0x110A57D, 
           entryLine: {_parent: <2>, 
                       _proto: {#356429}, 
                       viewCObject: 0x110A58C, 
                       viewFlags: 10753, 
                       viewBounds: {#4418301}, 
                       text: "2"}, 
           labelLine: {_parent: <2>, 
                       _proto: {#356569}, 
                       viewCObject: 0x110A5C2, 
                       text: "?Num Beeps:", 
                       viewFont: {@100}, 
                       viewBounds: {#44181E1}}, 
           width: 73, 
           indent: 75, 
           height: 13}
Now let's look at the value of the text slot in numBeeps. Expecting to find the value of 2, we get a surprise instead:

numBeeps.text
#4632AD   ""
There isn't a text slot in the numBeeps view or template. So the value of numBeeps.text must be coming from the protoLabelInputLine itself. Notice, however, that there does seem to be a text slot with the value "2" in numBeeps.entryLine. But of course! For a protoLabelInputLine, the input text isn't found in the text slot of the labelInputLine view, but in the text slot of the child view where the input is actually done (see "protoLabelInputLine" on page 177). With this bit of fresh information we can now modify the code in the buttonClickScript. Our code should actually be

func()
begin
   local beeps :=
      StringToNumber(numBeeps.entryLine.text);
   for i := 1 to beeps do
      :SysBeep();
end

An online version of Programming for the Newton using Macintosh, 2nd ed. ©1996, 1994, Julie McKeehan and Neil Rhodes.

Last modified: 1 DEC 1996