6.4. Code and the Run Handler
So far, we've talked about blocks, and in particular about script object and handler definitions, as the constituents of a script. But of course there's more to a script than that: there's the actual code, the commands, the stuff that does something. From a visual point of view, code can appear anywhere. But wherever code appears, if you work your way up the levels of nesting, sooner or later you'll always come to either a handler or a script object. That's what the code is really inside of.
set x to 1 on outer( ) set xx to 1 script s set xxx to 1 on sayHowdy( ) display dialog "howdy" end sayHowdy set xxxx to 1 end script set xxxxx to 1 end outer set xxxxxx to 1
That script is exactly the same as an earlier example, except that I've added code lines, so that given the structure of the script (a handler in a script object in a handler), at least one line of code appears in every place where code can possibly appear. All the lines of code are set commands, except for the display dialog command in the middle. So now consider the line "set xx to 1." Where is it, structurally? It's inside the handler outer. You can do this for every line of code.
This little game is significant because the regions demarcated by the handler and script object definitions are also regions of scope. The line "set xx to 1" talks about a variable called xx. Because of how and where this line occurs, there are strict rules about what parts of the script can and can't see this variable xx. (Those are the rules I'll talk about in Chapter 10.)
Now, here's a curious fact. Strictly speaking, code doesn't occur just anywhere. Code can occur only in a handler. Once again, this may sound weird, but it is actually very elegant, because it makes the structure of a script nice and uniform. There's just one problem: it looks like I must be lying. Surely the first line of the script, "set x to 1," is not in a handler, right? It's in a script object, because it's at the top level of the script and the script as a whole is itself a script object . Similarly, the line "set xxx to 1" is at the top level of a script object, and not in a handler. Right?
Wrong. It turns out that there's a secret kind of handler you can't see. The rule is that every script object has a handler called run. This special handler is called the script object's run handler . If you like, you can actually express this run handler explicitly. The script object is then said to have an explicit run handler .
Here is a script with an explicit run handler:
on run display dialog "howdy" end run
You will observe that the on run statement lacks any parentheses, unlike other handler definitions we've seen. The run handler is special and doesn't use parentheses.
If a script object has no explicit run handler, then it has an implicit run handler . Here is a script with an implicit run handler:
display dialog "howdy"
Those two scripts are almost exactly the same. They are both scripts with a run handler containing exactly one line of code (the display dialog command). They both do exactly the same thing. The difference is that in one case the run handler is explicit, and in the other the run handler is implicit.
When a script (or script object) runs, what runs is its run handler. This will be much more significant to you when I talk more about script objects, but for now just concentrate on your script as a whole. When you execute a script, whether by pressing the Run button in a script window in a script editor application, or by giving a compiled script file to a script runner and calling the script through the interface, or whatever, what runs is that script's top-level run handler, whether implicit or explicit. The two previous scripts with display dialog do exactly the same thing, whether the run handler is implicit or explicit.
A script object (including a script as a whole) has exactly one run handler. Therefore it cannot have both an explicit and an implicit run handler. That would be ridiculous. It would also be illegal. This code will not compile:
on run display dialog "howdy" end run display dialog "howdy"
If you try to compile that, you will get one of the very few truly informative error messages in the whole of AppleScript: "The run handler is specified more than once , or there were top-level commands in addition to the run handler."
So, if there is an explicit run handler in a script object, that script object cannot have any top-level code. If there is no explicit run handler in a script object, that script can have top-level code and the lines of that code are its run handler (implicit).
A script object definition or a handler definition are not code. (This is another way in which these blocks are special.) The code inside them is code, of course; but they themselves are not. Thus the following script is legal and does not constitute an attempt to have two run handlers:
on run display dialog "howdy" end run on sayHowdy( ) display dialog "hello" end sayHowdy script s display dialog "bonjour" end script
When a run handler is implicit, a script object definition or a handler definition at the top level is in some sense not really inside it. They really are at the top level. One way you know this is that otherwise you could never define a handler at the top level of a script. Remember, a handler nested directly in a handler is illegal. But this code is legal even though there's an implicit run handler, because the sayHowdy handler definition isn't really inside it.
on sayHowdy( ) display dialog "howdy" end sayHowdy
But this won't compile:
on run on sayHowdy( ) display dialog "howdy" end sayHowdy end run -- compile-time error: Expected "end" but found "on"
The run handler is explicit, and the sayHowdy definition is nested inside itand a handler in a handler is illegal.
We thus have something of a paradox, because an implicit run handler can surround a handler definition without containing it in a way that makes it illegal:
set x to 1 on sayHowdy( ) display dialog "howdy" end sayHowdy set x to 2
In that script, the first line and the last line are in the implicit run handler, but the sayHowdy handler definition is at the top level.
For most purposes, it's not important to be constantly aware of the implicit run handler. It's easier to pretend that code can occur at the top level of a script object. So, for example, when we talk about scope, it will make most sense to speak of "set x to 1" in the preceding example as being at the top level of the script. For purposes of scope (and in other ways) an implicit run handler and an explicit run handler don't behave exactly alike. But you can't have both, so you do need to know they exist.