Previous Page
Next Page

9.6. Syntax of Defining and Calling a Handler

The way a handler is defined (in the on line) states how many parameters the handler takes (and also supplies names for variables in the handler to which the parameter values will be assigned during a call). A call to the handler must correspond, supplying parameters correctly. It is a runtime error to call a handler with fewer parameters than the definition of the handler requires:

on greet(what)
    display dialog what
end greet
greet( ) -- error: {} doesn't match the parameters 
 {what} for greet

The nitty-gritty of how a handler's definition states how many parameters there are, and how a corresponding call to that handler must be phrased, is remarkably complicated. There are actually four cases that must be distinguished (though you are most likely to use only the first two in handlers that you define). I'll discuss these four cases in a moment, but first I want to talk about the problem of optional parameters.

9.6.1. Optional Parameters

Officially, there is no way to declare a parameter optional in AppleScript. On the other hand, you really don't need a way to do this, because a parameter can be a list or a record, which can have any number of items. (Gosh, all we need is a shift command and this would be Perl!)

For example, here's a handler that calculates the area of a rectangle given the lengths of the two sides. If you pass the length of only one side, the rectangle is assumed to be a square:

on area(L)
    set a to item 1 of L
    if (count L) = 2 then
        set b to item 2 of L
    else
        set b to item 1 of L
    end if
    return a * b
end area
area({3, 4}) -- 12
area({3}) -- 9

A record used as a parameter is often an even better way to simulate optional parameters because it allows you to simulate default values for missing parameters as well. A single concatenation lets you merge the defaults into the parameter record without upsetting the values that are already there (see "Record" in Chapter 13; use of this device in this context was suggested to me by Scott Babcock). For example:

on greet(R)
    set defaults to {greeting:"Hello", whom:"World"}
    set R to R & defaults
    display dialog R's greeting & ", " & R's whom & "!"
end greet
greet({whom:"Everybody"}) -- Hello, Everybody!
greet({greeting:"Howdy"}) -- Howdy, World!
greet({greeting:"Bonjour", whom:"Monde"}) -- Bonjour, Monde!
greet({}) -- Hello, World!

It is not an error to include extra parameters in a handler call. They are simply ignored by the handler. You might think this feature would be useless, but it's not. It allows the caller to be somewhat ignorant of the details of the handler it's calling. This is valuable particularly when the caller and the handler are written by two different people. Suppose, for example, that I'm a script runner and you are supplying the script for me to run. I can specify in the documentation that I'm going to call the person handler in your script, with four parameters: firstName, lastName, age, and place. You can define your person handler, omitting any parameters that you happen not to care about. So, I might call your handler like this:

person given firstName:"Matt", lastName:"Neuburg", age:51, place:"Ojai"

But you might define your handler like this:

on person given firstName:fir, lastName:las
    display dialog fir & space & las
end person

That's legal. (The application Phlink actually works like this; see Chapter 26.)

9.6.2. No Parameters

If a handler takes no parameters, the name of the handler in the definition is followed by empty parentheses:

on handlerWithNoParameters( )
    -- code
end handlerWithNoParameters

The call consists of the name of the handler followed by empty parentheses:

handlerWithNoParameters( )

9.6.3. Positional Parameters

Positional parameters are unnamed . The pairing between each parameter value passed and the local variable in the handler that receives it is performed by looking at their respective positions: the first parameter is assigned to the first variable, the second parameter is assigned to second variable, and so forth.

If a handler takes positional parameters , the name of the handler in the definition is followed by one or more variable names in parentheses, separated by commas:

on handlerWithOneParameter(x)
    -- code
end handlerWithOneParameter
on handlerWithFourParameters(a, b, c, d)
    -- code
end handlerWithFourParameters

The call then consists of the name of the handler followed by parentheses containing the parameter value or values, separated by commas:

handlerWithOneParameter(7)
handlerWithFourParameters("hey", "ho", "hey", "nonny no")

9.6.4. Prepositional Parameters

Prepositional parameters are also called labeled parameters . Each parameter is preceded by a preposition drawn from the list in Table 9-1.

Table 9-1. The prepositions

above

beneath

into

against

beside

on

apart from

between

onto

around

by

out of

aside from

for

over

at

from

thru

below

instead of

under


In addition to the prepositions in Table 9-1, there is also a preposition of. This is used in a special way: if you use it, it must come first, and there must be more than one parameter. (This odd rule seems to be due to a mistake in the original design of AppleScript. In AppleScript 1.0, the of parameter was intended as a way of distinguishing the "direct object," the handler's main parameter. Then it was realized that where there was just one parameter and it was the of parameter, an unresolvable ambiguity with the of operator existed. So AppleScript 1.1 resolved the ambiguity by forbidding of to be used that way. But no alternative way of distinguishing the direct object was supplied, so in a sense this feature has been broken ever since.)

If a handler has prepositional parameters, the name of the handler in the definition is followed by a preposition and a variable name, and then possibly another preposition and another variable name, and so on.

In the call, the name of the handler is followed by a preposition and a value, and then possibly another preposition and another value, and so forth. The prepositions used must match those of the definition, but they may appear in any order, except for of, which must be first if it appears at all.

Here are some examples of handlers with prepositional parameters and calls to them:

on firstLetter from aWord
    return character 1 of aWord
end firstLetter
display dialog (firstLetter from "hello")
 
on sum of x beside y
    return x + y
end sum
display dialog (sum of 1 beside 2)
 
on stopping by woods on aSnowyEvening
    return woods & aSnowyEvening
end stopping
display dialog (stopping on "horse" by "farm")

In the call, if the value you wish to pass is a boolean (Chapter 13), you may use with or without (to indicate true and false respectively) followed by the preposition. If you don't use this syntax, AppleScript will probably use it for you when it compiles the script: any prepositional parameters for which you pass the literal value true or false will end up as with or without followed by the preposition. Multiple with parameters or without parameters can be joined using and. This looks quite silly when the labels are prepositions, but here goes:

on stopping by woods on aSnowyEvening
    if woods and aSnowyEvening then
        return "lovely, dark and deep"
    else
        return "ugly and shallow"
    end if
end stopping
display dialog (stopping with on and by)
display dialog (stopping with by without on)

There's a weird bug (at least I presume it's a bug) that allows you to define a handler with prepositional parameters but call it using positional parameters. The bug operates only in the case where you use of for the first parameter in the definition (which means that you also have to have a second parameter in the definition). When you call the handler with positional parameters, they all arrive as a list in the first parameter; the second parameter is empty. This bug was pointed out to me by Michael Terry, who notes that you can take advantage of it to implement a handler that can take any number of parameters. As your positional parameters are going to end up in a list anyway, there can be any number of them. AppleScript won't complain, no matter how few parameters there are (including none), and they all end up in a list in your handler, so none of the values is lost. For example:

on sum of L beside dummy
    set total to 0
    repeat with aNumber in L
        set total to total + aNumber
    end repeat
    return total
end sum
sum(1, 2, 3, 4, 5, 6, 7) -- 28

(On some systems, the bug is not present, and there's an error at runtime. On others, AppleScript may crash. But this trick works fine on Tiger. Still, I wouldn't rely on it, because if it is a bug, it might be fixed some day, breaking the example.)

9.6.5. Named Parameters

Named parameters are a way to take advantage of labeled parameters while escaping the circumscribed repertoire of built-in prepositions (Table 9-1). With named parameters, you get to make up your own labels, though of course you mustn't use a word that's already reserved by the language for something else.

You may combine named parameters with prepositional parameters; if you do, the named parameters must come after the prepositional parameters.

The syntax for defining named parameters is colon-basedthe name of the parameter is followed by a colon, which is followed by the name of the handler variable:

on handlerName ... given paramName1:varName1, paramName2:varName2, ...

The first ellipsis in that syntax schema is the definition for the prepositional parameters, if there are any. The second ellipsis is for as many further named parameters as you like.

The call works just the same way: the keyword given must appear, it must appear after all prepositional parameters if there are any, and the same colon-based syntax is used. The named parameters may appear in any order:

handlerName ... given paramName1:value1, paramName2:value2, ...

As with prepositional parameters, boolean values can be passed using with or without and the parameter name, and for these there is no need to say given. Multiple with parameters or without parameters can be joined by using and. Again, AppleScript will use this syntax for you if you pass the literal value TRue or false.

Here are some examples of handlers with named parameters, and calls to them.

on sum given theOne:x, theOther:y
    return x + y
end sum
display dialog (sum given theOther:2, theOne:3)
 
on scout given loyal:loyal, trustworthy:trustworthy
    if loyal and trustworthy then
        return "eagle"
    else
        return "sparrow"
    end if
end scout
display dialog (scout with loyal and trustworthy)
 
on area of side1 beside side2 given measure:m
    return ((side1 * side2) as string) & space & m
end area
area of 4 beside 5 given measure:"inches" -- "20 inches"

The first example demonstrates that the order of parameters in the call is free. The second example demonstrates the use of with, and also shows that the parameter labels can be the same as the local variable names. The third examples shows prepositional and named parameters used together.


Previous Page
Next Page