In Part II you learned the AppleScript language. It's essential to know this language if you're going to write AppleScript code; yet, ironically, the AppleScript language on its own won't get you very far. That's because AppleScript, all by itself, doesn't do very much; its real power and purpose lies in communicating with scriptable applications, which provide powers that AppleScript lacks. In order that you, the AppleScript programmer, may harness its powers, a scriptable application extends the vocabulary of the AppleScript language. For example, AppleScript can't make a new folder on your hard drive, but the Finder can; therefore the Finder extends AppleScript's vocabulary, supplementing it with terms such as make
and folder
so that you can use AppleScript to command it (the Finder) to make a folder. This extended vocabulary is called a scriptable application's terminology
. A dictionary
is the means by which a scriptable application or scripting addition lets the world know how it extends AppleScript's vocabulary.
A dictionary has two audiences—AppleScript and the AppleScript programmer. Let's consider how each of these audiences uses a dictionary:
AppleScript uses an application's dictionary at compile time to look up the terms that the programmer uses. In this way, AppleScript confirms that the terms really exist; as they don't exist within AppleScript itself, AppleScript cannot know without a dictionary that the programmer isn't just talking nonsense. At the same time, AppleScript uses the dictionary to resolve the terms into their corresponding Apple event form; otherwise, it wouldn't know what actual Apple event messages to send to the scriptable application at runtime. And it uses the dictionary when decompiling, to translate those Apple event terms back into English-like words for display to the programmer.
The AppleScript programmer studies a human-readable display of a dictionary to learn what English-like terms, beyond those built into the AppleScript language itself, may be used when targeting a particular application, or in the presence of a particular scripting addition. Studying a dictionary to figure out how to use AppleScript to get an application to do your bidding is a major part of the typical AppleScript programming experience. Such study must often be combined with experimentation when the dictionary is insufficiently informative.
The dictionary mechanism pervades the life of the AppleScript programmer in several ways:
The dictionary is used by AppleScript for resolution of terminology . Therefore you have to make certain that your script points AppleScript properly to any required dictionaries, and that it can find these dictionaries at key moments (compilation, decompilation, and runtime).
The dictionaries of scriptable applications and scripting additions invade the available namespace. This invasion creates clashes between terminology used in one dictionary and another, or between one dictionary and the terms that you, the programmer, would like to use. The result is a high probability that something you'd like to say will be misinterpreted or forbidden.
The dictionary is usually your only documentation on how to communicate with a given application. But a dictionary, in and of itself, by the very nature of its format, is almost certainly going to fulfill this function inadequately. To make matters worse, dictionaries are often badly written or downright misleading. You therefore face the paradox of being dependent upon the dictionary for information that may be insufficient, hard to understand, or wrong.
This chapter discusses all these aspects of dictionaries. See also Chapter 3 for the format in which a dictionary is stored and for the implications when a needed dictionary is missing. See "Target" in Chapter 11, and "Tell" and "Using Terms From" in Chapter 19, for details on how the target is determined, how messages are sent, and how AppleScript decides what application's dictionary it will use to resolve terminology. In Chapter 21 I'll talk more about what scripting additions and their dictionaries add to the mix, and in Chapter 27 we'll actually construct a small dictionary to make an application scriptable. Also, see Appendix A for an example of a real programmer struggling valiantly with a real dictionary.
Example 20-1 exhibits some common patterns of terminology usage. With it, we'll model AppleScript's interaction with dictionaries during the process of compilation.
Example 20-1. Simple terminology resolution
tell application "Finder" set c to display dialog ((count folders) as string) end tell
Compilation of code like Example 20-1 proceeds in two distinct stages:
The tell block causes AppleScript to locate a particular application and load its dictionary.
The terms inside the tell block are resolved.
Let's consider these stages one at a time.
As AppleScript's compiler encounters a tell block (or a terms block) targeting a literal application, it attempts to locate this application and load its dictionary. If the compiler can't find the application, it will ask the user where it is; if the user cancels out of this process, refusing to choose an application, AppleScript will not compile the script (see "Missing External Referents" in Chapter 3).
AppleScript will proceed happily at this point, provided that it can find the application, or the user chooses an application for it—any application. The compiler has not yet reached the stage of trying to resolve any actual terminology, so it doesn't matter whether there is any terminology to resolve, or even whether the application has a dictionary. All that matters so far is that the application referred to in code should be identified with some actual application.
Loading a dictionary takes time, and may even require launching the application in question, which takes even more time. Once the current instance of the AppleScript scripting component has already loaded a particular application's dictionary, however, it doesn't need to do so again, because it now has a copy of the dictionary cached in memory. These are some of the reasons why a script typically takes longer to compile the first time.
Presume that the compiler has reached the interior of the innermost tell block or terms block that caused a dictionary to be loaded. The compiler now proceeds to resolve the actual terms of the block.
Only one application dictionary is involved in the resolution of terminology in a given context. This is the dictionary corresponding to the innermost surrounding terms block or tell block where an application is explicitly specified. Let's call this the innermost application dictionary .
The interaction between nested terms blocks and tell blocks in determining the target and the innermost application dictionary was described in Chapter 11 and Chapter 19. Recall that iTunes is not targeted in this code:
tell application "iTunes" tell application "Finder" count folders end tell end tell
So iTunes's dictionary will be loaded at compile time (and this will necessitate launching iTunes if it isn't running already) but it will not be consulted because it isn't targeted. iTunes knows nothing of folders, but this doesn't matter. On the other hand, it does matter in a case like this:
tell application "Finder"
using terms from application "iTunes"
count folders -- error: The variable folders is not defined
end using terms from
end tell
The terms block deliberately perverts AppleScript's use of dictionaries. AppleScript, instructed explicitly to look in iTunes's dictionary, never learns that folder
is defined in the Finder's dictionary, nor does it find folder
in iTunes's dictionary. Thus it thinks folders
is the name of a variable; that variable is undefined at runtime, causing an error.
Every term used in a given context must be found in a dictionary in order to be resolved. But the innermost application dictionary is not the only place where AppleScript may have to look, because some of the terms may be defined elsewhere. The hunt for terminology thus involves several steps. Here's how it goes:
The commands get
and set
(and sometimes copy
) are specially short-circuited and are not sought in any dictionary.
The term is sought in the innermost application dictionary. (But see "No Terminology Clash," later in this chapter.)
The term is sought in AppleScript's own dictionary (described later in this chapter, under "The 'aeut' Resource").
The term is sought in the dictionaries of any scripting additions that are present.
The term is sought in the script itself.
Let's trace the resolution of the terms in Example 20-1, according to these rules:
The term set
(and its parameter to
) are short-circuited (rule 1).
The term folder
is defined in the Finder's dictionary (rule 2).
The term count
appears both in the Finder's dictionary and in AppleScript's own dictionary. The former is used in the present case (rule 2).
The term string
appears in AppleScript's own dictionary (rule 3).
The term display dialog
is defined in a scripting addition's dictionary (rule 4).
The term c
isn't found anywhere, so it's sought in the script, and is resolved as the name of an implicitly defined local variable (rule 5).
As part of the terminology resolution process, AppleScript translates terms into their corresponding four-letter codes and constructs any Apple events that are called for (Chapter 3). So in Example 20-1, the Finder defines folder as 'cfol'
and count as 'core\cnte'
, and AppleScript constructs this Apple event:
core\cnte { kocl:'cfol', ----:'null'( ) }
The Apple event is written into the compiled code, ready to be sent to the Finder at runtime.