In the few spare moments I’ve had over the past several weeks, I’ve followed some discussions of Word and AppleScript both in the comments to my earlier post and in the Microsoft newsgroups. A particularly good discussion, with input from both Matt Neuburg and Paul Berkowitz, can be found here.

Both Matt and Paul have pointed out that there is a very strong correspondence between AppleScript and Word’s VBA (Visual Basic for Applications) implementation. The same is true for both PowerPoint and Excel, though not for Entourage. There is no VBA implementation in Entourage.

I want to talk about why AppleScript so closely resembles VBA in Word, Excel and PowerPoint, but I first want to take a step back and talk about objects and object models.  These are terms you’ll find quite often in any discussion of scripting regardless of the application or the scripting environment.  It has a lot to do with how programmers think about the data they manipulate and how they manipulate it.

An “object” is any entity that can respond to some form of input or command, and often has some form of data associated with it.  Word, as an application, is an object.  The documents that you have open in Word are objects.  The windows that display those documents are objects.  The sections within those documents are objects.  The paragraphs within the sections are objects.  In formal terms, an object is both the data it contains and the operations that can be performed on the data it contains.  We use the word “properties” to talk about the data, and the word “methods” (or “commands” in AppleScript parlance) to talk about the operations that can be performed on that data.

An “object model” is a conceptual definition, or description, of how the objects in an application are related to each other.  Quite often this takes shape in the form of a “containment hierarchy”.  The “containment hierarchy” is really just a fancy way of saying that some objects are properties of other objects.  For example, in Word, a paragraph is a property of the document object.  This relationship can include the notion of collections (or “plural forms” in AppleScript parlance).  Really, a collection is nothing more than a group of similar objects within the same container.

Any given object model is very application centric.  Word’s object model, for example, has some significant differences from, say, BBEdit’s object model, and that’s not just because Word does some things that BBEdit doesn’t.  The way one describes the “selection” object is highly dependant upon how the concept of a “selection” is implemented in that application.  The “selection” object for a drawing program, for example, is going to be very different from the “selection” object in a text editor.

Commands and how they relate to objects are also extremely application centric.  For example, when you tell an application to “select foo of bar,” what does that really mean?  Are you telling “foo of bar” to select itself, are you telling the selection object to incorporate “foo of bar,” or are you telling the application to change its selection to foo of bar?  The answer to that question will depend largely on the application you’re working with (though, in Word, it generally means that you’re asking “foo of bar” to become the selection).

The important point in all of this is that, at the conceptual level, the object model one defines for any given application depends on the application, and not the scripting environment or scripting language you use to expose that object model.  Had Word never had a VBA implementation of its object model, Word’s AppleScript implementation of that object model would not have differed substantially from its current implementation.  Any differences would be more attributable to the way particular individuals approached the design of the object model than they would be attributable to differences between VBA and AppleScript.

This is the primary reason why there is such a strong correspondence between the VBA implementation and the AppleScript implementation of the object models in Word, Excel and PowerPoint.  One could, if one wanted to, implement VBA as a pass-through to an AppleScript implementation of these object models, though there is a fundamental difference between VBA and AppleScript that would tend to favor doing things the other way around.

To understand this fundamental difference, we have to understand something known as “application intercommunication,” or “interprocess communication” (the word “process” is really just a synonym for “application program”).  Within modern operating systems, applications have fences built around them.  The idea is to keep bugs in one application from affecting the behavior of other applications running on the system.  Within this design, if applications are going to communicate with each other, we need to give them a way to pass information back and forth over the fences that have been built around them.

With AppleScript, interprocess communication is done via AppleEvents.  Every command that you send to Word via AppleScript is packaged up into an AppleEvent.  When Word’s done processing that AppleEvent, it packages up a reply, puts the reply in the AppleEvent, and sends it back “over the fence” as it were.  With VBA, interprocess communication is done using the Component Object Model (or COM).  COM provides programming interfaces that are amenable to being called directly within the programming languages we use to write the applications themselves.  COM is often referred to as a “binary interface,” because it lends itself to direct programmatic manipulation in this way.

In essence, COM was designed so that objects in the system would look an awful lot like they way objects are implemented in the C++ programming language.  In fact, you can take a file written in the COM Object Description Language (ODL) and, using a command-line tool, generate header files that can be included directly into C++ code.

For interprocess communication, COM has a technical problem that I won’t describe in detail, but involves the fact that applications have fences built around them.  Basically, one program cannot directly call a binary interface that’s provided by another program.  That would be like reaching through the fence instead of passing something over the fence.  To solve this, COM uses something called “marshalling”.  None of this has to be done for AppleScript, because AppleScript doesn’t provide the same kind of binary interface.

So, COM is messy for interprocess communication, but it’s really nice for intraprocess communication.  AppleScript isn’t quite so messy when it comes to interprocess communication, but it’s a royal PITA when it comes to intraprocess communication.  What do I mean by intraprocess communication?  Well intraprocess communication is how various software components in an application, and in any shared libraries used by that application, communicate with each other.  In this case, the kind of binary interface that COM provides is perfect.  To the programmer, the COM objects look like any other component in the program (which is where the name “COM” comes from).

This is, in fact, how all of the external wizards that we ship are implemented.  They’re written in C++ and they talk to Word, or Excel or PowerPoint, via the binary interfaces each of the applications expose through the VBA implantations of their respective object models.

For those of you who are familiar with COM and the standard programming interfaces that COM defines, I should point out that all of these interfaces are “dual dispatch” interfaces.  While every object does implement the standard IDispatch interface, every method and every property of every object is also available through direct programmatic manipulation through individual interfaces that descend from IDispatch.  The point is that neither the Wizards we ship nor the AppleScript implementation goes through IDispatch::Invoke.  Rather, both call the appropriate method or property implementation directly on the appropriate object itself.

If you don’t understand anything in the above paragraph, don’t worry.  The important point to understand is that, in light of the previous point about the design of an object model for any given application, it makes perfect sense to use an existing VBA implementation of an object model to expose that same object model via AppleScript.  In fact, not only does it make perfect sense to do this, it’s the most efficient way you can possibly do the job.  The VBA implementation already packages up the object model in a manner that lends itself to direct programmatic manipulation.

It makes so much sense to do things this way that you can even get lazy about it.  You can design a language that describes your object model both in VBA and AppleScript terms, and then you can write a tool that parses a description file and generates the code for you.  In only a “few” (quoted because “few” is relative—there are 215 distinct objects in Word’s object model, and I won’t even begin to count all the properties and methods on those objects) instances do you have to get your hands dirty and write some code yourself.

As an insight into Jim Murphy’s sense of humor, the object description language is called “Sid,” and the tool that compiles files written in that language is called “Nancy.”  One of these days, I’m going to have to go rent that movie.

 

Rick