(NS)AppleScript Sucks

EDITED TO ADD 2007-11-02: Some of the issues discussed in this article, like Script Editor messing with your code, have been addressed in Leopard. But until the majority of OS X users are on Leopard, they’re still a problem for most people. Also, I think it’s worth documenting just how many issues AppleScript tools and support have had. So I am not planning on removing “fixed” problems, at least for a while. This article is about why I don’t like using AppleScript. Historical issues are part of that dislike. It’s a matter of trust and expectations.

The NSAppleScript honeymoon is over. I don’t like AppleScript, I don’t like NSAppleScript.

John Grubber has a good article on AppleScript’s “natural language” failings. An excerpt (emphasis mine):

INTERPOLATION ON THE FAILED EXPERIMENT THAT IS APPLESCRIPT’S ENGLISH-LIKE SYNTAX

… It was a grand and noble idea to create an English-like programming language, one that would seem approachable and unintimidating to the common user. But in this regard, AppleScript has proven to be a miserable and utter failure.

In English, these two statements ought to be considered synonymous:

path of fonts folder of user domain
path to fonts folder from user domain
But in AppleScript, they are not, and rather are brittlely dependent on the current context…

The idea was, and I suppose still is, that AppleScript’s English-like facade frees you from worrying about computer-science-y jargon like classes and objects and properties and commands, and allows you to just say what you mean and have it just work.

But saying what you mean, in English, almost never “just works” and compiles successfully as AppleScript, and so to be productive you still have to understand all of the ways that AppleScript actually works. But this is difficult, because the language syntax is optimized for English-likeness, rather than being optimized for making it clear just what the fuck is actually going on.

This is why Python and JavaScript, two other scripting language of roughly the same vintage as AppleScript, are not only better languages than AppleScript, but are easier than AppleScript, even though neither is very English-like at all.

Amen, brother!

Many months ago I had written “In general, AppleScript code is extremely readable, and relatively close to english.” I do not believe this anymore, and have since revised the article. Too often AppleScript clashes with English syntax. Here are a couple of example AppleScript strings (both from current code v0.26):
@"tell application \"Adium\" to my status type as Unicode text";
@"set volume without output muted"

The first sentence is missing a verb (are we getting or setting?); the second lacks an object (set volume to what?). (It turns out the first gets a string from Adium, describing my status {“offline”, “away”, “available”, etc.}; the second un-mutes sound for the whole system.)

I don’t like the NSAppleScript class because it is extra un-thread-safe. That is to say, you can only use it on from the main thread (hint: performSelectorOnMainThread:). No amount of @synchronized blocks will keep you from crashing (intermittently!) if you use an NSAppleScript anywhere else. There is a workaround that won’t block anything, but the cure is worse then the disease. You can use an NSTask to have the osascript program interpret the script for you. This won’t block anything, but it will be take a long time, and is resource intensive.

Dynamically constructing an NSAppleScript is dangerous. There is no way to pass an array of arguments directly into the script, as can be done with an NSTask. Any quotation marks “” need to be carefully escaped. For example, the AppleScript built from [NSString stringWithFormat:@"tell application \"iChat\" to set status message to \"%@\"", message]; will fail spectacularly if message contains quotation marks.

AppleScript is also leaky. This is another reason why you should follow Apple’s advice, and always cache compiled NSAppleScript objects. Not only is it a time-penalty to recompile them; but you will also leak memory every time a new NSAppleScript object is created.

The Script Editor application sucks. Compared to any modern IDE it’s a bad joke. It’s not just that it’s underpowered — it’s that it’s obviously lacking polish. Error messages are often ungrammatical. A dead giveaway of poor design. (Although I get a perverse laugh out of “Syntax Error \ User canceled.”)

Script Editor won’t let you save or open code that won’t compile! This is a dangerous and serious bug. A user should always be able to save their data at any time. It turns out that Script Editor actually saves source code as a compiled script! So if your code can’t compile right now you can’t save it! I’ve essentially lost a script I wrote for the obsolete Fire IM client, because I can’t even read it without the program being present on my system, since AppleScript can’t “compile” it without finding the program.

Which hilights another problem with Script Editor — it likes to change your code; even if it means breaking it on other computers. If I type POSIX file "/Users/", it is automatically replaced by file "Macintosh HD:Users" when the script is compiled and saved. This is wrong. POSIX file "/Users/" is portable across any MacOSX computer that has the /Users/ directory — which is every desktop computer. But file "Macintosh HD:Users" relies on the computer having it’s root-directory reside on a disk named “Macintosh HD” — and this isn’t always true. The two statements are equavalent on my computer, but not on every computer — Script Editor is in error for forcing the change.

AppleScript comment syntax is broken:
(* this is a block comment in AppleScript*)
— and this is an inline comment
(* this comment should be valid — but it’s not because of the dash, and it will keep your script from running *)

In Objective-C mixing inline and block comments is permitted, /* this comment ... //won't break anything */ Even if no programming language allowed inline comment headers inside a block comment, AppleScript would still suck for doing this. That’s because unlike “//”, “–” is an actual punctuation mark. You can expect to find it inside a comment. (NOTE: “–” should be two single-dash characters, not the long-dash it was turned into. Unfortunately my blogging software always “upgrades” ASCII equivalents of punctuation marks.)

Paths in AppleScript are incompatible with everything else, and hard to work with. AppleScript uses pre-MacOSX style “:”-delimited paths. But every other popular programming language I know of does not not, and nether do any command-line utilities, or any shell I’m aware of. That makes using a command-line utility — which should be a simple task in any scripting language — a chore in AppleScript. For example, let’s say I was using perl, and I had a variable $src that held the path to some file. I could write:
`ditto -ckX --rsrc $src $src.zip`
to create a zip-file of it that preserved all its special MacOSX filesystem settings. $src could have been defined as “~/file”, or it could have come from another command-line utility, etc.

But in AppleScript I would have to write:
do shell script "ditto -ckX --rsrc " & POSIX path of src & " " & POSIX path of src & ".zip"
All the extra ‘<POSIX path of‘ nonsense makes for some unwieldy code. Worse yet AppleScripts’s support of POSIX path’s is deeply flawed. It won’t support ~ expansion. POSIX path of "~/file" resolves to file ":~:file", not file "Macintosh HD:Users:user:file" as it should. So all POSIX paths pased to an AppleScript have to be absolute.

What’s particularly funny about this, is that dragging a file into Script Editor inserts the poorly supported POSIX path to the file into the editor. This is another example of how poorly-designed Apple’s AppleScript IDE is.

AppleScript has no built-in regular expression support. As far as I know it’s the only modern scripting language without regex support. To use a regex in AppleScript, you have to invoke a command-line utility to do it for you, using the do shell script "" command. This introduces a level of “-escaping hell. It’s also very slow. Regex (un)support alone is plenty of reason to use anything but AppleScript for writing scripts.

The concept of libraries in AppleScript is deeply broken at the design level. Because AppleScript is such a minimal language, almost everything is done by asking other programs to do something. in AppleScript, functionality does not come from nested Libraries, but from “Scripting Additions” provided by other applications. This means there isn’t a logical and powerful library hierarchy that makes things easier. Instead you get an irrational flat list of modules, including every application on the system that is scriptable:
AppleScript Library Madness
It’s not always clear who you should “tell” to give you what you need. tell application "Finder" to get every application process gives a list of every running process. But why are we asking the Finder to give us that? The Finder is a file browser, and the “face” of the computer. If I wanted to see this list, I would launch Activity Monitor, or “top”, not mess around in the Finder. Functionality is not logically organized in AppleScript, and this makes writing code hard, because it’s difficult to find what you need.

AppleScript uses an application’s name to identify an application; unfortunately application names are a complex mess on MacOSX.

…there are at least five application names floating around, at least in concept: (1) the file name the Finder sees, which in the case of an application package is the package (bundle) name; (2) the name of the executable inside the package, (3) the long name used in many places for display purposes only; (4) the short name used as the application menu title and in a few other places where a long name won’t fit for display purposes; and (5) the process name of a running application. They aren’t always the same…

–From a message by Bill Cheeseman.

I still like the idea of directly embeding snippets of a scripting language into directly into Cocoa code. That’s a very powerful idea. But I do not like the leaky, and decidedly un-threadsafe implementation of NSAppleScript. I also dislike the AppleScript language and the AppleScript “IDE”. If AppleScript wasn’t currently the best way to script most Mac applications I wouldn’t use it.

Further Reading:
AppleScript likes to mess with your code
Computer Languages aren’t Human Languages

Advertisements
Explore posts in the same categories: AppleScript, Cocoa, MacOSX, NSAppleScript, Objective-C, Programming

7 Comments on “(NS)AppleScript Sucks”


  1. […] Apple programs and OS X itself. EDITED TO ADD: Unless you use threads in your program. Here is a more sobering perspective, written several months after this […]

  2. has Says:

    Consider using objc-appscript to send Apple events directly from ObjC. The latest revision can safely be used on non-main threads.

    http://appscript.sourceforge.net/objc-appscript.html


  3. […] AppleScript is a pretty poor language on it’s own. Usually I see it being used to get some specific thing done. In other words, generally AppleScripts are essentially expressions, used to get or set a single value; rarely are they sub-programs. This is whyExpressions are such a good fit. Explore posts in the same categories: AppleScript, Design, MacOSX, NSAppleScript, Programming, Research, Sample Code, Tips […]


  4. […] hope this regression is an isolated incident. It’s just one more reason I’m not fond of AppleScript. Explore posts in the same categories: AppleScript, Entertainment, Leopard, MacOSX, Programming, […]


  5. Thanks a million for this advice! The best, clearest answers on the subject I could google up.

  6. thereepr Says:

    Apple really should fade out applescript. It’s a nice idea, but overall is an epic fail

  7. Jerry Says:

    Leopard may have fixed some of these issues, but not the worst of them. Keywords mean different things in different contexts, for pete’s sake. Plain English has no defined order of operations, and hell if I know where the parentheses should go. Certainly not where Script Editor puts them. I spent an hour bashing my head against the keyboard because I wrote ‘write myText as class utf8 to myfile’ when I should have written ‘write myText to myFile as class utf8’. Am I coercing the file or the data it contains? I’m still not sure.

    English is a lovely language, one I aspire to make a living using, in part because it has so many shade of gray, so many nuances of interpretation. However, that makes it a horrible, horrible programming language. With AppleScript you still have all the syntactic constraints of a programming language, but they’re wrapped in a language that is simply not designed for that. Any ‘friendly’ feeling you get from the language is almost immediately supplanted by the frustration of not being able to predict how your code is going to be interpreted.

    Give me thirty minutes and a good reference with any programming language and I will be able to function. I think this is true of any experienced programmer. Unless that language is AppleScript.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: