AppleScript Gotchas, Exceptions to the rules, explained...

How to use the reopen event in a stay-open application

When a user runs (or opens) a script application”for example, by double-clicking on its icon, or selecting its icon and choosing the Open command from the File menu”the Finder calls the applet’s run handler and executes it. If the applet has no explicit run handler, any code at the root level of the script is run as an “implicit” run handler.

Script writers sometimes assume that the run handler will be called every time an applet is run in this manner. Surprise! The assumption is not correct in the case of stay-open applications that are already running. When a running stay-open applet is double-clicked, nothing happens. See the Rerunning Applets for the solution.

How to avoid errors when using a loop variable

When looping through a list in a repeat with block using the with form, be careful how you test the loop variable. The following code snippet looks like it should return the value 2, but it doesn’t because the test for equality with 2 is never satisfied:


repeat with i in {1, 2, 3}
   if i is 2 then
      exit repeat
   end if
end repeat
i --> item 3 of {1, 2, 3}

As you see from the final value of i, the snippet looped all the way through the list and exited only when the list was exhausted. To get to the bottom of the problem, try this:


repeat with i in {1, 2, 3}
   class of i --> integer
   i --> item 1 of {1, 2, 3}, item 2 of {1, 2, 3}, etc.
   if i is 2 then --it never is 2!
      exit repeat
   end if
end repeat
i --> item 3 of {1, 2, 3}

Single-stepping through this snippet using an advance script editor, we see that the class property of each list element is reported as integer, which demonstrates that the loop variable is evaluated to its contents when determining its class. However, the loop variable is not evaluated to its contents when performing the equality test. So, to be safe, you should always test the contents of a loop variable, not the loop variable itself, like so:


repeat with i in {1, 2, 3}
   class of (contents of i) -->integer
   contents of i -->1, 2, etc.
   if contents of i is 2 then
      exit repeat
   end if
end repeat
contents of i -->2

Or, in simpler form:


repeat with i in {1, 2, 3}
   if contents of i is 2 then
      exit repeat
   end if
end repeat
contents of i --2

Or, in the safest form (from the viewpoint of a forgetful scripter), always reset the loop variable to its contents before attempting to use its value for any purpose:


repeat with i in {1, 2, 3}
   set i to contents of i
   if i is 2 then
      exit repeat
   end if
end repeat
i -->2

You might think this is a bug in AppleScript, but it isn’t. A loop variable in the with form of the repeat loop is a reference to an object, not the value of the object. Like many AppleScript gotchas, this one is actually explained in the AppleScript Language Guide: “To get the value of an item in the list, you must use the contents of operator” (emphasis added). Moral: read the manual!”not once, but twice, thrice, or whatever it takes.