[ Team LiB ] |
8.4 Pass By ReferenceParameters passed to a handler, and the value returned from a handler, are normally passed by value in AppleScript. This means that a copy of the value is made, and it is the copy that arrives at the destination scope. But four datatypes—lists, records, dates, and script objects—when they are passed as parameters to a handler, are passed by reference. This means that no copy is made; the handler's scope and the caller's scope both end up with access to the very same value, rather as if it were a global. Any change made to the parameter by the handler is also made back in the context of the caller. For example: on extend(LL)
set end of LL to "Jack"
end extend
set L to {"Mannie", "Moe"}
extend(L)
L -- {"Mannie", "Moe", "Jack"}
Notice that we didn't capture the value of the handler call extend( ). The handler extend was able to modify the list L directly. After the call, L has been changed in the caller's context, even though the caller didn't change it. It makes sense that lists, records, dates, and script objects can be passed by reference, since these are the only mutable datatypes—the only datatypes whose values can be modified in place, as opposed to being replaced wholesale. But it is a little odd that they are passed by reference automatically. Passing by reference gives the handler great power over the parameter, which the handler can misuse. To prevent accidents, it is up to you to remember that list, record, date, and script object parameters are passed by reference, and that things you do in a handler to such parameters have an effect outside the handler. What about values that are not lists, records, dates, or script objects? How can they be passed by reference? The nearest thing to a solution, which unfortunately works only when the variable in question is a global, is AppleScript's ability to pass (by value) a reference to a variable (see Chapter 11). The syntax consists of the phrase a reference to, followed by the name of a global. The handler must explicitly set the contents of the reference whose variable value it wants to change. For example: on increment(y)
set contents of y to y + 1
end increment
set x to 5
increment(a reference to x)
display dialog x -- 6
Since only a global can be passed by reference in this way, it could be argued that one might as well use an actual global, and not bother passing anything at all: on increment( ) global param set param to param + 1 end increment set param to 5 increment( ) display dialog param This approach, however, depends on both scopes knowing the name of the global, so it lacks generality. Nevertheless, there are situations where a global is the best approach, as when a script must maintain state between calls to different handlers; we'll see examples in Chapter 24. You cannot return a handler's value by reference. Well, you can, but it's usually pointless. It's true that this works: on extend(LL)
set end of LL to "Moe"
return LL
end extend
set L to {"Mannie"}
set LLL to extend(L)
set end of LLL to "Jack"
L -- {"Mannie", "Moe", "Jack"}
It's clear that LLL has arrived by reference in the sense that changing it changes L. But the only reason this works is that we're just returning from extend( ) the very same reference that was passed in to start with! And we could have obtained that reference without calling the handler at all (in this case, simply by using set, as you'll see in Section 13.12). This was never a value local to the handler. It makes no sense to return by reference a value local to a handler, because by definition such a value is destroyed when the handler finishes executing; there is nothing for the reference to refer to. |
[ Team LiB ] |