[ Team LiB ] |
9.7 InheritanceScript objects may be linked into a chain of inheritance. If one script object inherits from another, the second is said to be the parent of the first. If a message is sent to a script object and it doesn't know how to obey it, the message is passed along to its parent to see whether it can obey it. A message here is simply an attempt to access any top-level entity. To link two script objects explicitly into a chain of inheritance, initialize the parent property of one to point to the other.
In this example, we explicitly arrange two script objects, mommy and baby, into an inheritance chain (by initializing baby's parent property). We can then tell baby to execute a handler that it doesn't have, but which mommy does have. Here we go: script mommy
on talk( )
display dialog "How do you do?"
end talk
end script
script baby
property parent : mommy
end script
baby's talk( ) -- How do you do?
In that example, we told the child from outside to execute a handler that it doesn't have but the parent does. The child can also tell itself to execute such a handler: script mommy
on talk( )
display dialog "How do you do?"
end talk
end script
script baby
property parent : mommy
talk( )
end script
run baby -- How do you do?
Getting and setting properties works the same way. In this example, we get and set the value of a property of baby that baby doesn't have: script mommy property address : "123 Main Street" end script script baby property parent : mommy end script display dialog baby's address -- 123 Main Street set baby's address to "234 Chestnut Street" display dialog mommy's address -- 234 Chestnut Street Again, the same thing can be done from code within the child; but now the name of the property must be prefixed with the keyword my. Otherwise, since there is no property declaration in scope for this name, the name is assumed to be the name of a local variable. The keyword my says: "This is a top-level entity of the script object running this code." Thus, if AppleScript fails to find such a top-level entity in the script object itself, it looks in the script object's parent. script mommy
property address : "123 Main Street"
end script
script baby
property parent : mommy
on tellAddress( )
display dialog my address
end tellAddress
end script
baby's tellAddress( ) -- 123 Main Street
Similarly, we can refer to a script object that the child doesn't have but the parent does: script mommy
script talk
display dialog "How do you do?"
end script
end script
script baby
property parent : mommy
end script
run baby's talk -- How do you do?
Again, if the child wants to do this, it must use my: script mommy
script talk
display dialog "How do you do?"
end script
end script
script baby
property parent : mommy
run my talk
end script
run baby -- How do you do?
9.7.1 PolymorphismWhen code refers to a top-level entity, the search for this top-level entity starts in the script object to which the message that caused this code to run was originally sent. This is called polymorphism. You may have to use the keyword my to get polymorphism to operate (and it's probably a good idea to use it in any case). An example will clarify: script mommy
on tellWeight( )
display dialog my weight
end tellWeight
end script
script baby
property parent : mommy
property weight : "9 pounds"
end script
baby's tellWeight( ) -- 9 pounds
We ask baby to tell us its weight, but baby doesn't know how to do this, so the message is passed along to the parent, mommy. There is now an attempt to access my weight. But mommy has no top-level entity called weight. However, the search for weight starts with baby, because our original message was to baby (mommy is involved only because of inheritance). The property is found and the code works. To see why my is important here, consider this code: script mommy
property weight : "120 pounds"
on tellWeight( )
display dialog weight
end tellWeight
end script
script baby
property parent : mommy
property weight : "9 pounds"
end script
baby's tellWeight( ) -- 120 pounds
There is no my before the name weight, and mommy's declaration for the property weight is in scope, so the name is simply identified with this property; polymorphism never has a chance to operate. The reason for the "poly" in the name "polymorphism" is that the response to the parent's use of a term can take many different forms. A parent whose code is running because of inheritance has no idea of this fact, so it has no idea what its own code will do. For example: script mommy property weight : "120 pounds" on tellWeight( ) display dialog my weight end tellWeight end script script baby property parent : mommy property weight : "9 pounds" end script script baby2 property parent : mommy property weight : "8 pounds" end script mommy's tellWeight( ) -- 120 pounds baby's tellWeight( ) -- 9 pounds baby2's tellWeight( ) -- 8 pounds In that example, the parental phrase my weight gets three different interpretations, depending solely on what script object was addressed originally. 9.7.2 ContinueA child can call an inherited handler by using the continue command. The syntax is the keyword continue followed by a complete handler call (parameters and all). You might wonder why this is needed, since after all the child can just send a message directly to the parent by referring to the parent as parent. But there's a crucial difference. If a message is sent to the parent by referring to it as parent, that's a new message with a new target. On the other hand, the continue command takes place in the context of the current message and the current target; it passes the current flow of control up the inheritance chain. Thus, the one breaks polymorphism, the other does not. This example demonstrates the difference: script mommy
property weight : "120 pounds"
on tellWeight( )
display dialog my weight
end tellWeight
end script
script baby
property parent : mommy
property weight : "9 pounds"
parent's tellWeight( )
continue tellWeight( )
end script
run baby -- 120 pounds, 9 pounds
9.7.3 The Implicit Parent ChainA script object without an explicitly specified parent has as its parent the script as a whole. We took advantage of this fact earlier (see the end of Section 7.5.1) to refer to a top-level script property. Thus: property x : 5
script myScript
property x : 10
display dialog my parent's x
end script
run myScript -- 5
But there's a parent beyond that. The script as a whole has as its parent the AppleScript scripting component. This appears to your code as a script object called AppleScript. The AppleScript script object has some properties that you can access. Normally you do this without having to refer to AppleScript explicitly, because these properties are globally in scope; it's as if every script were surrounded by another invisible script with property declarations for these properties. But in a context where a name overshadows the name of one of these properties, it would be necessary to be explicit, in order to jump past the current scope and up to the level of AppleScript: set pi to 3 display dialog pi -- 3 display dialog AppleScript's pi -- 3.141592... display dialog parent's pi -- 3.141592... The AppleScript script object is also where the built-in verbs live. For example, when you say: get 3 + 4 the get command travels up the inheritance chain until it reaches the AppleScript scripting component, which knows how to obey it. The AppleScript scripting component has a parent too—the current application. This is the host application that summoned the AppleScript scripting component to begin with. The current application is the absolute top level, and can be referred to in code as current application. For example: display dialog (get name of current application) -- Script Editor
To sum up: script myScript my parent -- «script», the anonymous top level my parent's parent -- «script AppleScript» my parent's parent's parent -- current application end script run myScript Observe that scope-wise containment is not implicit parenthood: script myScript script myInnerScript my parent -- the anonymous top-level script, not myScript end script run myInnerScript end script run myScript Nor can a contained script object be made to have a containing script object as its parent. AppleScript will balk if you try this: script myScript script myInnerScript property parent: myScript -- compile-time error end script end script I think the reason for this restriction must be that the demands of parenthood would conflict irresolvably with the rules of scoping. |
[ Team LiB ] |