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.
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.)
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( )
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")
Prepositional parameters are also called labeled parameters . Each parameter is preceded by a preposition drawn from the list in Table 9-1.
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.)
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-based—the name of the parameter is followed by a colon, which is followed by the name of the handler variable:
onhandlerName
... givenparamName1
: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
... givenparamName1
: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.