Previous Page
Next Page

9.2. Returned Value

When a handler is executed, it may return a value. This value is the handler's result .

The term result is used here in a technical sense. A handler may do other things besides return a result, and these other things may be quite significant in the world outside of the handler; but although these things may result from calling the handler, in a nontechnical sense, technically they are the handler's side effects, not its result. Thus, if you call a handler that erases your hard drive and returns the number 1, you might say, "The result of calling the handler was that my hard drive was erased," but technically you'd be wrong: the result was 1; the erasure of your hard drive was a side effect . (Clearly a side effect can be much more important than a result.)


When a handler is called, the result of executing the handler is essentially substituted as the value of the call that executed the handler.

For example:

on getRam( )
    set bytes to system attribute "ram "
    return bytes div (2 ^ 20)
end getRam

The handler getram returns the amount of RAM installed on the user's machine, in megabytes. On my machine, it returns the number 1024. This means that a call to getram( ) can presently be used wherever I would use the number 1024; in effect, it is the number 1024. For example:

on getRam( )
    set bytes to system attribute "ram "
    return bytes div (2 ^ 20)
end getRam
display dialog "You have " & getRam( ) & "MB of RAM. Wow!"

The call to getram( ) in the last line behaves exactly as the number 1024 would behave in this context: it is a number, it is implicitly coerced to a string and concatenated with the other two strings (as explained under "Concatenation Operator" in Chapter 15), and the full resulting string is displayed to the user.

The value returned by a handler is determined in one of two ways:


An explicit return

The handler, in the course of execution, encounters a line consisting of the keyword return, possibly followed by a value. At that point execution of the handler ceases, and the returned value is whatever follows the return keyword (which could be nothing, in which case no value is returned).


An implicit result

The handler finishes executing without ever encountering an explicit return. In that case, the returned value is the result of the last-executed line of the handler.

For the same reason that I recommend that you not use the result keyword (see "Result" in Chapter 5), I recommend that you not use a handler's ability to return an implicit result. If you're going to capture a handler's result, use an explicit return statement in the handler.


If a handler returns no value, there is no error; but in that case it is a runtime error to attempt to use the call as if it had a value. The status of such a call is similar to that of a variable that has never been assigned a value (see "Declaration and Definition of Variables" in Chapter 7). So, for example, there's nothing wrong with this:

on noValue( )
    return
end noValue
set x to noValue( )

After that, even if x was previously defined, it is now undefined. That outcome is actually useful if you wanted to undefine x; there's no other way to do it. But remember, a subsequent attempt to fetch x's value will generate a runtime error:

on noValue( )
    return
end noValue
set x to 1
set x to noValue( )
set x to x + 1 -- error: The variable x is not defined

The result of a handler is volatile. It is substituted for the call, but the call itself is not storage (it isn't a variable), so the result is then lost. If you wish to use the result of a handler again later, it is up to you to capture it at the time you make the callfor example, by setting a variable to it. Of course, you could just call the handler again; but there are good reasons why this strategy might not be right:

  • The handler might yields different results on different occasions; if you wanted the particular result of a particular call, calling it again won't do.

  • The handler might do other things besides return a result (side effects); to perform these side effects again might not be good, or might not make sense.

  • Storing a result and using it later is far more efficient than calling the handler a second time.

So, for example, this code works, but it is very poor code:

on getRam( )
    set bytes to system attribute "ram "
    return bytes div (2 ^ 20)
end getRam
set s to "You have " & getRam( ) & "MB of RAM. Wow! "
set s to s & getRam( ) & "MB is a lot!"
display dialog s

The handler is called twice to get the same unchanging result, which is very inefficient. The right way would be more like this:

on getRam( )
    set bytes to system attribute "ram "
    return bytes div (2 ^ 20)
end getRam
set myRam to getRam( )
set s to "You have " & myRam & "MB of RAM. Wow! "
set s to s & myRam & "MB is a lot!"
display dialog s

The second version calls the handler and immediately stores the result in a variable. Now it suffices to fetch the value from the variable each time it is needed.

The result of a handler may be ignored, though, if the caller doesn't care about it (or knows that no value will be returned). In this case the handler is called entirely for its side effects. Generally the call will appear as the only thing in the line:

eraseMyHardDisk( )

The same is equally true for the run handler of a script object (or a script as a whole), whether implicit or explicit. A run handler is a handler, and can have a result (possibly a useful result). After you run a script in a script editor application, the result is displayed; if no return statement was encountered, the result displayed is the implicit result of the run handler of the script as a whole. (This fact can be useful in developing and testing a script; see "Implicit Result" in Chapter 5.) A script runner, on the other hand, will usually ignore a script's result, neither capturing it nor displaying it; the script is executed entirely for its side effects.


Previous Page
Next Page