Is it Possible to Use AppleScriptObjc In Simple/Non-App Scripts?

Greetings,

I’m trying to figure out if it’s possible to use ASOC/AppleScriptObjc/Cocoa-Applescript (whatever the kids are calling it these days) in a basic script that can be run anywhere any Applescript can be run, especially scripts evoked from other apps.

In particular, I need scripts that have a functioning “run” handler that can be evoked from within applications.

Problem Story: Unlike the apparent vast majority of Applescript users, I am a highly experienced programmer in Objective-C but naive about Applescript for all but the most trivial uses.

Now, I have a need to do some serious data management in DevonTHINK Pro, an organizer app I’ve used for over decade. I have literally thousands of notes, snips, books, bookmarks, you-nameit crammed in there, and I need an automated system to analyze, archive, purge and structure the data equivalent of a junk yard pile.

DevonTHINK Pro is nicely scriptable and I’ve already neatened things up considerably but in trying to go farther, I hit a wall of Applescript’s built in limitations… or my understanding of Applescript. Either way, solutions whose logic I can implement in literal minutes in Objective-c take me literally hours in Applescript. It’s very frustrating and I just don’t have the time to burn.

What I’ve Tried: I found I can use ASOC in Scripting Libraries such as this trivial example I created in ASObjC Explorer 3.2.3 (Mavericks, Demo)

use AppleScript version "2.3.2"
use scripting additions
use framework "Foundation"
-- use framework "AppKit"

on captialize(aStr)
	set nsStr to current application's NSString's stringWithString:aStr
	set retStr to nsStr's capitalizedString()
	return retStr as string
end captialize

Calling Script:

use theLib : script "^" -- required
use scripting additions

tell theLib
	set result to it's captialize("this should be capitialized")
end tell
Result:
--> "This Should Be Capitialized"

This works, but oddly fragile (I’ll detail in a separate post,) but even if wasn’t fragile, I dislike the practical aspects of managing dependencies that come with using shared code. Been there, done that, still have the faded T-shirt.

I’d strongly prefer to manage integral scripts with no dependencies. It makes everything in small, seldom edited code like scripts so much easier in the long run. Plus, it makes it easy to share scripts if you just have to send one file.

The very fact that I can save and use a short snippet of Applescript as a library from ASObjC Explorer suggest it is possible but my attempts to replicate a non-library version in Applescript Editor and Script Debugger were embarrassing failures that I hastily deleted lest I be tempted to expose my ineptitude in a public post.

The contents of one of the package for the libraries created by ASObjc Explorer is just a complied scrpt file (which looks like a binary plist format) and a standard info.plist with the key “OSAAppleScriptObjCEnabled” set to true. Therefore, I suspect, it’s quite easy to set one of the editors to produce scripts without nibs or a gui, if one knows the magic words.

Which I don’t.

Summation:
I need:
(1) Applescripts which use ASOC/AppleScriptObjc/Cocoa-Applescript so I can use the Cocoa API to quickly crank out solutions.
(2) Independent scripts that can be evoked inside scriptable applications e.g. DevonTHINK Pro, Text Wrangler etc
(2) Scripts that have a functioning “run” handler (and callable handlers in general like pure Applescript scripts.)

So, who has an answer? I’d prefer to work with Applescript Editor or Xcode because I don’t foresee really doing enough scripting going forward to justify ASObjC Explorer or Script Debugger but I’ll take what I can get at this point.

Model: Macbook Pro Retina, 15-inch, Late 2013, 10.9.3
AppleScript: 2.3.2
Browser: Safari 537.78.2
Operating System: Mac OS X (10.8)

The only way to do it in Mavericks is via a script library, as your post outlined. But – you can embed the script library in the calling script (which might look odd in your sample, but is just a bog-standard AS script that can have run handlers, etc – you don’t have to use the use business, but can use ‘tell script “”’ instead).

If your ultimate destination is an applet, just make a Script Libraries folder in the applet’s Resources folder. If it’s going to be run as a script attached to an app somehow, most apps should accept a .scptd instead of a .scpt, so you can still embed it. (And if they don’t, it’s a bug.)

There’s one catch in the latter: if the app tries to change the default target (which includes any sandboxed apps), the ASObjC code won’t work.

And just to be clear: AppleScriptObjC-based apps written in Xcode are different in several respects, and in some cases require different syntax. They don’t have a functioning run handler. (And Xcode is an appalling AppleScript editor to work in because its syntax styling is borked and it never shows compiled code.)

Shane Stanely,

Thanks for the timely response.

Yes, that does seem to be the case. I think there is a means of making an ASObjc equivalent of a Foundation tool in Xcode but it will require a custom project with custom build settings. That will take sometime to set up and test.

I’ll probably just use script bundles.

Clarification: is “the app” the application calling the script e.g. DevonTHINK Pro in my example, or is the app the ASObjc app?

I think it is possible to provide a run handler inside Xcode with some work. The Script Editor’s Cocoa applet documentation says that run handler in the main script will be evoked. I did confirm that a run handler in main.scpt of an applet will trigger on launch but I haven’t tested if it responds to file drops or other passed parameters. I think you could do the same thing in Xcode, by adding a main.scpt and calling it from applicationWillFinishLaunching:

Agreed, but: (1) It’s a tool whose other functions I’m already highly familiar with. (2) All of Applescript feels cumbersome to work with, even in Script Debugger and ASOBjc Explorer, so a few added annoyances don’t feel that major (3) Long experience has taught me to bite the bullet and use standardized tools. That will be especially true if I do very little scripting from here on out. If I don’t use, say, ASOBjc Explorer for 3 months, I’ll forget how it works and have to retrain myself before I can actually get work done.

But who knows? Javascript for Automation looks to make Applescript/OSA more generically useful by giving the language more intrinsic power to perform without apps. Plus, the more my understanding of modern Applescript grows, the more possibilities I see, which might lead me to script more, which would justify the specialized tools.

Model: Macbook Pro Retina, 15-inch, Late 2013, 10.9.3
AppleScript: 2.3.2
Browser: Safari 537.78.2
Operating System: Mac OS X (10.8)

The app running the script. If it’s an applet, it’s the applet; if you’re running from an app’s script menu, or something like a Mail rule, it’s the app with the menu, or Mail. Ultimately there has to be an app running a script.

Yes, but that’s a bit of smoke-and-mirrors. You can look inside the app, and see the app delegate – it’s not run-only, so you can read the code. Basically applicationDidFinishLaunching: uses AppleScript’s load script command to load main.scpt, and then call its run handler.

That’s exactly how the applet in ASE was made. The app delegate is ASObjC, so the loaded script becomes ASObjC too.

You’re missing the point, or points. First, the kind of apps you produce in Xcode use ASObjC differently. A normal ASObjC-based library script is like any other script, with a parent of the current application. But in Xcode projects the parent of the scripts is set to a Cocoa class. (Presumably what actually happens is that at launch, the call to loadAppleScriptObjC in main.c loads the script file(s) and synthesizes Objective-C equivalents that then call the script. Whatever.) The different parentage means that in some cases you need to use different syntax.

Secondly, even if you want to write Xcode-style apps – for the interface, for example – it still makes more sense using ASE or some other editor as an external editor to Xcode, because it’s handling of AS is so bad. I understand the familiar tools argument, but it’s a bit like saying you’ll write essays in Photoshop because that’s what you’re familiar with. Most of the functions of Xcode just don’t apply, and those you are likely to need are missing.

I’m not saying you have to buy ASObjC Explorer – I’m saying that for scripts and applets Xcode is not a serious option. Use AppleScript Editor if you don’t want to spend anything.

No, there will still need to be apps. JXA is built on top of the same Apple event mechanism.

But JXA will be in Yosemite, and you’re assuming nothing will change in AS there. You ought to go look in the developer forums.

Right.

Agreed, but it doesn’t have to be the AppDelegate (I think.) From my superficial perusal of the ASOC framework, it looks like the real trigger is NSBundle’s loadApplecriptObjcScripts(sp?) method. You can load a bundle from Foundation and execute arbitrary code inside it, so I think I could configure the xib to run any arbitrary script in the bundle which would allow the ASOC equivalent a Foundation tool that might respond to a run handler.

But, I might be talking out of my hat.

Good point and probably a source of some of my confusion. I was looking at example code written and running in different environments.

It’s easy to forget Applescript’s highly unique attribute of running across multiple applications at once. I don’t think any other language/architecture really does that.

The scoping in Applescript and the resulting reference forms feels very counter intuitive to me. Probably another instance of knowing to much about other programming environments being an active impediment in Applescript.

Sigh, but I probably will, just because it’s nifty.

My only real hesitation about just buying every conceivable tool for Applescript is the time I fear I will burn using them. I have this little problem with Yak Shaving, and getting a shiny new toy prompts me to find a use for it. As a one man shop, there’s no boss to whip me back on task and all to often I find myself in the programming/time management equivalent of thinking , “well, one more drink can’t hurt,” and then waking up with a week later in strange room, strange bed and a strange person next to you.

(I suppose an enigmatic tattoo would be the code in this analogy. Yes, I’ve written hundreds of lines of code only to complete it and realize I don’t remember why I wrote it.)

BTW, I’ve found that using a looming timeline demo actually keeps me from Yak Shaving because the demo imposes a looming deadline I can’t escape without laying down some cold hard cash. It doesn’t matter if it’s $5 or $500, it’s that parting of the first $1 that serves psychologically. ( I wonder if you could extend that as business model along the lines of the Software as Service concept? )

FWIW, my problem with Applescript Editor sounds somewhat trivial but can be show stopping for me specifically. While it supports syntax coloring, it doesn’t, as far as I can tell, support changing the background color of the document to something other than white. I like to work with with bright colors on black because of some minor but annoying vision problems. It’s easier for me specifically to quickly single character typos on the black background.

Xcode, ASObjc explorer and Script Debugger all support a black background, which makes them easier to read but anything saved in those three it shows up in Applescript Editor as unreadable bright colors on a white background. (Affects QuickLook in the Finder as well.)

(That reminds me, I need to make another post in another part of the forum about that. Don’t bother to reply here.)

It seems to be a flat trade off between editing in Applescript Editor, with it’s superior syntax understanding but lack of the optimal color scheme and Xcode, with has the photonegative properties. So the fact that Xcode is in my muscle memory now so it doesn’t break my stream of thought like Applescript Editor still does, tips me toward Xcode.

Sorry, didn’t mean to convey that I thought otherwise. I don’t need Yet Another Scripting Language. If I want Javascript without the OSA, I’d just use Node or even JavascriptCore. I intended to convey that JXA, as a Javascript variant, has the more powerful standard language tools like arrays and hashes, independent of which app it is in or communicating with.

My main problem with Applescript is it’s lack of basic data constructs. (See below) I don’t have any problem with the actual OSA specific functions or any particular application’s commands.

I’ll do that. But even if they extend the core, non-application dependent Applescript, it’s still easier for me to work inside a “C”-ish syntax like Javascript than Applescript’s pseudo-natural language.

This immediate below is just to provide some context for my situation, in case it’s helpful for Shane or anyone else now or in the future. Feel free to ignore it.

I don’t wish to use ASOC to primarily for an interface. I’m coming at ASOC backwards from the way that probably 99% of it user’s do. As professional programmer in the Apple ecosystem, I have a good understanding of everything in the Apple ecosystem except Applescript. ASOC is designed to give people knowledgeable about Applescript, but not Objective-C, the ability to create full fledged interfaces and occasionally access Cocoa APIs.

After 18 years of working with Objective-c API from NextStep to OS 10.9, I can write a full fledged Objective-C app with my eyes closed. Instead, I need to (1) get access to large amounts of from data inside scriptable applications, (2) manipulate that data and (3) stick it back inside the apps.

Applescript does (1) and (3) near perfectly. It is (2) that is killing me.

Working in Applescript,[i] I spend the vast majority of my time writing generic data structuring, storage and manipulation code. [/i (Lots of logging/debugging code as well to watch the evolution of the data.)

Applescript was never intended for direct data manipulation. It was assumed all the heavy lifting would be done inside the scriptable apps. If we want to do data manipulation that the app’s developer created a command for, we’re golden. But if we want to do something with the data the developer didn’t anticipate, then we’re stuck with Applescript’s comparative weak and primative innate data structuring, storage and manipulation constructs e.g. list and records.

And it really trips me up

Over the last few years, I’ve done a rather lot of language tourism going through over two dozen languages just to check them out. In all of them, I was able to find the proper data constructs and quickly build code around them because most modern languages have the same general set of core data constructs. The code I crank out isn’t pretty and certainly not a glowing exemplar of the languages features but it works and I can understand it.

I can do that because I spent the last mumble-mumble decades developing the skill to instantly generate generic algorithms based on the assumption that I have those powerful collections tools available somewhere in the language or api. For a small scale piece of code like an Applescript, my trained brain just instantly pops out a full formed algorithm for any specific data manipulation. Don’t have to think about it, all I have to do is type it in.

But in Applescript, all those instant algorithms break because Applescript doesn’t have even the most basic (by contemporary standards) data containers e.g. Arrays, Sets, Hashes/Dictionaries, etc and their associated default operations e.g. insert at index, arbitrary runtime Hash/Dictionary, keys of a dictionary etc. I have to toss out the instant modern algorithm and try to remember how “we did it back in the day.”

It’s like that old party gag where you ask someone to describe exactly which parts of their legs and feet they move and in what exact order, when they walk. Then have them walk across the room while narrating their the movements of their body. Most people can’t do it without seriously stuttering and/or stumbling. The very act of paying attention to a task we do without thinking derails the task.

We walk without thinking and programmers generate basic algorithms without thinking because, let’s face it, we probably code more than we walk (if the bulge in my gut is any indication.)

Sure, there are work arounds in Applescript but it often requires ridiculous amounts of hack code that (at least in my naive hands,) is very fragile, or I have to do the Cargo Cult programming bit and use code or additions whose limitation and quirks I don’t really understand.

However, if I use ASOC to drop into Objective-c with it’s modern constructs, the code becomes very easy.

For example, I needed to create an set of folders that would group files based on the first character in the their names i.e. “A”,“B”,“1” etc. In Applescript, that sprawled into, IIRC over 200, lines of code that took me longer to debug than it did to write and even then I didn’t trust it. So, I used ASObjc Explorer to create a little library that wrapped a NSMutableDictionary and collapsed those 200 lines down to around 30. Runs fast and is easy to test and debug.

So, while Xcode might suck at actual Applescript, for anything big or with a gui, I plan to only be using Applescript for the bits of code where I communicate with other apps, and stay in Objective-c the rest of the time, so Xcode’s Applescript limitations will be less annoying.

FWIW, I will observe that it’s very hard to find any ASOC materials aimed at actual programmers. All the resources and examples assume the user knows something about Applescript but nothing about the Objective-C API. If you have the opposite knowledge base, you just have to figure it out on your own.

Sort of. loadAppleScriptObjC loads the scripts as Cocoa classes, so your AS handlers become effectively Cocoa methods.

When I used to teach AS classes, it was usually much harder to teach people with a programming background. Some even seemed to take it personally.


Yep – it can make a huge difference.

Well there aren’t a lot of ASObjC resources period.

But I’ve always found it strange how so many developers don’t think automation matters, and therefore don’t bother implementing scripting. I know it’s a lot of work to do properly, but Cocoa scripting makes a certain level relatively simple.

@TechZen:

The AppleScript language is first-class for Apple event IPC, and sucks for everything else. Trying to raise it to the level of even Objective-C (no peach itself) for general programming work is an exercise in futility. Unfortunately, Apple’s miserable failure to provide other languages with competent Apple event support means that whatever you do is going to be painful to some degree, though depending on your requirements some are more painful than others:

  1. Use ObjC with ScriptingBridge. Caveat: SB is a half-baked, half-broken POS that only works up to a point, then it poops on you.

  2. Use JavaScript for Automation. Caveat: JXA is a half-baked, half-broken POS that only works up to a point, then it poops on you.

  3. Use ObjC, and call into AS via ASOC for the IPC stuff. It requires a bit of fiddling to set up, and you’ll pay a bit of a toll when crossing the bridge, but AppleScript remains the only supported option that can speak Apple events correctly, so this is the least dreadful of the supported options** for anything non-trivial. (I would not touch #1 or #2 for serious production work.)

Assuming you’ve already got an existing ObjC-based project, here’s how to add an ASOC-based class to it:

  1. In Targets > APPNAME > Build Phases > Link Binary With Libraries, add the AppleScriptObjC.framework.

  2. In Supporting Files > main.m, add the import and load lines as shown:


#import <Cocoa/Cocoa.h>
#import <AppleScriptObjC/AppleScriptObjC.h>

int main(int argc, const char * argv[]) {
	[[NSBundle mainBundle] loadAppleScriptObjectiveCScripts];
	return NSApplicationMain(argc, argv);
}

  1. To define an ASOC-based class named MyStuff that’s callable from ObjC, create a MyStuff.h interface file that declares its public methods:

// MyStuff.h

#import <Cocoa/Cocoa.h>

@interface MyStuff : NSObject

// (note: C primitives are only automatically bridged when calling from AS into ObjC; 
// AS-based methods with boolean/integer/real parameters or results use NSNumber*)

-(NSNumber *)square:(NSNumber *)aNumber;

@end

along with a MyStuff.applescript file containing its implementation:


-- MyStuff.applescript

script MyStuff

	property parent : class "NSObject"

	on square_(aNumber)
		return aNumber ^ 2
	end square_

end script
 
  1. Because the MyStuff class doesn’t have an ObjC implementation, the linker can’t link your ObjC code to it at build-time. Instead, you have to use NSClassFromString() to look up the class object at run-time:

#import "MyClass.h"

...

MyStuff *stuff = [[NSClassFromString(@"MyStuff") alloc] init];

Otherwise it’s pretty much indistinguishable from a native ObjC class in normal use:


NSNumber *result = [stuff square: @3];
NSLog(@"Result: %@", result);

Shane’s the go-to guy for all things ASOC-related; he’s even written a book on it.

As to grokking AppleScript, specifically the application scripting stuff: If you’re coming from an OOP background, the key is realizing that Apple event IPC uses RPC plus simple relational queries, not OOP semantics. OO programmers automatically assume it’s the latter since the corresponding AS syntax looks rather OO-ish, and then get totally confused and frustrated when it behaves in fundamentally non-OO ways. Or, to paraphrase Dobzhansky: “Nothing in AppleScript makes sense except in light of relational queries.” Think of AppleScript’s object specifiers (aka “references”, or “chunk expressions”) as roughly comparable to C#'s LINQ expressions, and it’ll start to make sense.

HTH

** The other option was appscript, which unlike SB did know how to speak AEs correctly and was a proven production-quality alternative to AppleScript. Unfortunately, Apple’s War On Carbon means I no longer officially support it or recommend its use, though it does demonstrate just how incompetent the AppleScript team’s work is by comparison.

It’s not strange at all. Competent developers do a cost-vs-benefit analysis when deciding whether or not to implement a particular feature, so if you want them to do it then either:

  1. Throw lots of revenue at them to implement it, in which case they’ll do it for the paycheck. Or:

  2. Turn them into major users of that technology, in which case they’ll do it out of love and self-interest.

The AppleScript team have utterly failed to build an audience amongst professional programmers over the years, even though such folks should logically be some of its biggest and most enthusiastic consumers. Just look at the enduring popularity of Unix shell scripting, which is positively primitive by comparison. Or count all the Mac-based Python and Ruby users out there, and ask yourself why virtually none of them are doing application automation today, even though OS X has included Apple event bindings for the last seven years (if anything the number’s actually decreased over that time).

So, since programmers get no benefit from the AppleScript stack themselves, what motive do they have to support it? Hell, I’m a fifteen-year AppleScript user, professional developer, and longtime booster, and I’m completely disgusted at the state of it, so I can hardly blame mainstream application developers for steering well clear.

It’s kinda of hard not to feel your ego crumble a bit when you’ve spent mumble-mumble years becoming a skilled programmer only to be flummoxed by something aimed at non-programmers. It’s like a formula 500 driver not being able to drive golf cart.

It’s all the more galling because, as I noted above, the programmers often knows the exact algorithm need to solve a problem if only they can do the right song and dance to get Applescript to implement it.

Non-programmers don’t have that experience. They’re thrilled with “hello world.” By the above analogy, they’re ten year olds turned loose with golf carts and their having a grand time whizzing around the park.

I think this frustration on the part of programmers probably makes them leery of spending to much effort on making their apps scriptable. After all, their intuition will naturally be, “If its this hard for programmers, imagine how hard it will be for naive end users!”

It takes some experience with ends user and Applescript to learn that isn’t necessarily so.

(Off topic but if you will indulge me)

I think that all of Applescripts adoption problems boil down to one thing: Unpredictability.

Every step in the development of an Applescript solution, from the developer trying to decide what level of scripting support to write into an app, to an end user trying to decide whether or not to pay for scripting support, all the way to down to an individual end user trying to solve a particular problem, Applescript presents utterly unpredictable money/time cost in return for equally unpredictable benefits.

People will pay dear in money/ time for hard to implement solutions if those solutions have a track record of predictable payoff but they dig in their heals when asked to slap down even trivial amounts of money/time on unpredictable gamble.

And nearly everything with Applescript is a gamble.

It starts with the developer. The real value add from Applescript is not from automation, recording or customizing existing features, but in allowing the app to do something it really wasn’t designed to because the developer didn’t anticipate the need. Nobody at Adobe or Quark back in the early 90s put in Applescript with the idea that their apps would someday depend on being linked to the apps of other companies.

It’s an obvious Catch-22. If the developer knows end users will need a feature, he’ll just build it into the app. If he doesn’t know, he can’t provide it in scripting save “accidentally” by spending the time/money to make virtually every facet of the app accessible via scripts.

Worse, there is a certain minimal but impossible to predefine level of scripting support needed to make the app usefully scriptable for a critical level of end users. Any level below that threshold adds little value and wont’ kick of a feedback loop that causes uses to value the app. Just one specific scripting feature or the lack thereoff can make or break and app on scripting. Developers must just guess both as to the degree and the specifics of scripting power to provide (and the cost of such to roll into the total) and simply gamble on the chance of return.

For the end user, it’s impossible to figure out how much value scripting adds to an app before purchase and therefore, how much of a premium to spend on app that provides scripting vs a cheaper one that does not.

That is particularly true of new and novel apps that nobody has used before. Since most users won’t use scripting anyway, most end users won’t even consider it as a value. For power users, if the scripting features of a particular app is of particular value because it slots into an existing niche in a scripted tool chain then the absence of the scripting feature is a deal breaker but it so, the developer will no to provide it. Such cases are rare. More often, power users won’t conceive of a particular need for a scripting solution. or until they’ve used the app for quite sometime and encountered a problem the developer didn’t anticipate. By time of the latter, they’ve already bought the app, so little economic feedback reaches the developer.

(BTW, People might say they want scripting but they won’t actually prioritize paying for it. Economist call that “stated” vs “revealed” preferences. Tech support is another common feature people claim to value but which seldom factors significantly into purchasing decisions. Only the minority who have paid big for failed tech support in the past will pay up front for it and let it be a deal breaker if they can’t get it.)

For both developers and end users then, paying for scripting is a leap of faith, paying up front for a feature that might never return any substantial benefit to anyone consummate with it’s cost. The market does not like such speculative leaps.

But the near fatal unpredictability with Applescript is the near complete inability of end users, even ones knowledgable about scripting in general , to predict whether Applescript can solve a particular problem before burning time and money trying to so.

Applescript is a “language” unlike any other. In other languages, you can eventually do anything. Other languages differ largely in how easy and reliably they make implementing different classes of solutions, not whether they can be performed at all. If you persist you will eventually get some return on your investment of time/money. It might be ugly but it will be something.

But Applescript doesn’t do everything and usually give you nothing. It is structurally limited by the decisions made by developers when they implemented scripting. It has no standard functional core beyond the barebones syntax. It’s designed to expose the internal operations of various different apps so its capabilities vary widely based on which mix of apps you use.

Worse near complete lack of standardization in function, relationship and nomenclature inside apps makes scripting dictionaries poor and often misleading guides and planning nearly impossible.

Applescript’s attempt to use vernacular nomenclature to describe by analogy software objects and functions leads to misperceptions instead of understanding because developers use the same word to symbolize functionally radical different software objects. E.g. “document” never means the same functional or data unit, and is never referenced the same way, in any two apps. Sometimes “opening” a document opens a file, other times it opens a window, other times it just creates an internal record and so on. Reading in a scripting dictionary that an app has a “document” class tells you exactly zero about what problem that class will let you solve.

Only the standard suite, the one developers get for free in the Cocoa framework, is moderately consistent app to app and even there “extensions” can destroy that consistency.

The random limitation and misleading documentation means the end user can’t reliably set down with an couple of apps and their scripting libraries to quickly and reliably determine if a particular problem can be solved in Applescript.

The only real way to see if a problem can be solved with Apple script is to spend the time/money trying to do so. Writing Applescript is more akin to reverse engineering than any other development task. Most of the time spent writing Applescript is spent investigating-by-experimentation what Applescript terms in any particular app actually mean and whether they will even do what you need them to do at all. By that time you’ve determined whether they will or want, the task is either largely complete or obviously impossible. Either way, you can never tell going in how much money/time you will burn for what outcome.

Many times over the last 22 years I’ve set down to the Applescript programming equivalent of a “three hour cruise,” based on a reading of a scripting dictionary and the knowledge of exactly how to algorithmically preform the task, only to find myself “years” later “marooned” still trying to make a ham radio out of vacuum tubes the scripting library directed me to find on the beach only to give up in a rage of frustration because what the developer called a vacuum tube was really a bleeping coconut.

I could provide anecdotes but the illuminating power of the anecdotes in the case of Applescript depends on the minute details of the intersection of my specific needs and specific application’s scripting capabilities and I don’t think you want to wade through all of that. Suffice to say that years of bitter experience has made me very, very leery of even attempting an Applescript solution. From many conversations over the years, I believe I am hardly alone in this regard. I would hazard that for every individual who has several success with Applescript, there are a couple of dozen who never had any success large enough to offset all the time wasted in the failures.

Given the right app, the right problem and the right person with the right skill set and enough time, Applescript can provide big gains but its more of a “black swan” or “perfect storm” like episode rather than something you can plan, and budget, on.

I’ve only been willing to clear the decks for a few weeks if necessary and force Applescript to work, writing Objective-c code and even contemplating writing scripting additions, because I have a massive task I must automate at virtually any cost. Its not a programming app so I personally am only able to get an Applescript solution at all because I am by chance a programmer and can write my own tools to provide functions that Applescript does not. This in an app with very extensive and well regarded levels of scripting support. Most users don’t have my skill set and I wouldn’t bother except in extraordinary circumstances.

I am hopeful that if I force myself over the critical threshold hump of minimum skill, Applescript will be more generally useful, but I’m dubious because to much depends on the developers having an incentive to make things more scriptable.

All this feeds back to developers of apps I purchase in the form of my ranking Applescript scriptablity far down on my list of features I use to judge whether to buy a particular app or note. Just having an app say it’s scriptable tells me little that lets me predict whether it will be useful or not and thus worth paying for. I can’t recall the last time I used scriptablity as a significant factor in a purchasing decision. Experience as simply taught me not to value Applescript as an app feature. Developers pickup on this and downgrade Applescript in their priorities to match mine and down goes Applescript in a negative feedback loop.

(On the other hand, the same years of experience have taught me that apps that use internal scripting with Python, Ruby, Javascript usually provide some value even if it means brushing up on language and learning a new API. By isolating to one app, with usually simple text input and output, they can make a predictable and easy to learn and use scripting API. Not as theoretically powerful as Applescript but more predictable in what problems the internal scripting engines can solve and therefore less wasteful of my time.)

On the developer side, I rank likewise Applescript low down the list of features I intend to include in my own apps. Usually, it’s because the kind of processing I can imagine for my type of apps would be a nightmare to implement and use in verbose and inconsistent Applescript. I have a couple of back burner projects which depend heavily on internal scripting but I didn’t even consider Applescript as an option and instead went with JavascriptCore because it was easier to implement, a more powerful a base language and more people know Javascript than Applescript.

I can predict the value of providing scripting in Javascript for my apps but can’t imagine, and therefore can’t predict a significant use for inter application Applescript. My potential user base can’t tell me either because they don’t know what the apps can do because they’re novel. Given the time/cost of Applescript and the unpredictable return, providing it would be crap shoot.

Javascript for Automation might drive me to reconsider but it’s not guaranteed. It would simplify the actual writing scripts compared to Applescript but the actual implementation would still be more difficult than using JavascriptCore (Javascript core can call directly into Objective-c with no scripting definitions necessary for translation. Way easier to implement and test.) While the added benefit remains unpredictable.

Perhaps most importantly however, JavascriptCore will work on iOS and to my knowledge (and expectation) Applescript does not and never will. For cross platform scripting, even just on Apple devices, Applescript remains a non-starter.

Hope I’ve provided some insight into why developers don’t invest in Applescript. Until the entire Applescript ecosystem provides more consistently predictable solutions, even just on Macs, I think it will remain marginalized over all. It’s shame because its potential is obvious.

I meant more in the abstract sense. I can understand developers looking at it and deciding it’s not going to pay, but I’ve been amazed at the number I’ve spoken to over the years who can’t see beyond the wonder of their own applications, and don’t see any point to the whole idea.

Or just make an informal protocol on NSObject.

I suspect you need to use NSNumber rather than NSInteger.

Obligatory derp. Fixed, thanks.

Again, the best way to realize the potential of a technology is to use it yourself. But professional programmers are effectively locked out of using Apple event-based automation themselves: using AppleScript is a giant PITA for them, using any other language is a farce due to busted incompetent AE bridging, and what little documentation exists totally lies and misleads them on how this stuff actually works. The AppleScript team have proven utterly incapable of either understanding or addressing these problems, as their “solution” to everything is to lie even harder. They’ve completely pissed me off with their shitty work and utter inability to acknowledge it’s shit, and I was one of Apple event automation’s biggest supporters and evangelists for many years, not just inside the AppleScript community but in the larger Python and Ruby worlds as well.

So I do not blame third-party application developers like the OP adopting embedded JavaScriptCore instead. Compared to what Apple event automation should be eJSC is a piss-poor alternative, but compared to how Apple event automation actually is it’s like a tiny drop of relative sanity in a great wild ocean of endless fuckup. Personally, my own advice to application developers thinking of adding scripting support would be to totally ignore AppleScript/JXA/Apple events/Cocoa Scripting/etc and adopt embedded JSCore, not because it’s a good solution (it’s not!) but because it’s the only chance users and developers who truly care about Mac automation have left of ever breaking the AS team’s incompetent death grip on it.

“Use embedded JavaScript”… ugh, I feel dirty just saying that.

p.s. @TechZen: you really should edit that screed into a nice tight argument with illustrative examples and see if you can get it published on one of the higher-profile Mac/tech sites as an opinion piece or critical review. (Feel free to pick my brains for what they’re worth; I’ve been thinking about doing something similar once 10.10 and JXA ships, but have yet to start writing anything.)

I should say that this is one of ASOC’s known deficiencies: ASOC treats all AS handler parameter and return values as type id.

Other bridges such as PyObjC allow you to define your method’s exact signature, e.g.:


class MyStuff(NSObject):

	@objc.signature("i@:i") # accept int parameter and returns int result
	def square_(aNumber):
		return aNumber ** 2

For instance, ASOC could easily support an optional method signatures property that allows AS users to declare custom method signatures where needed. e.g. Declaring that the square_ handler has the signature i@:i would tell the bridge to accept an int argument from ObjC and return an int result, or f@:f would tell it to accept and return 64-bit floats, and so on:


script MyStuff

	property parent : class "NSObject"

	property method signatures : {square_:"i@:i"}

	on square_(aNumber)
		return aNumber ^ 2
	end square_

end script

Feel free to file a feature request if this would be useful to you.

Seems like something useful, but more work than just using objects in the first place.

Not being able to specify signatures limits your ability to pass ASOC-based objects to other ObjC APIs, since it can only receive messages with primitive arguments if those method signatures have been pre-specified by a .bridgesupport file. e.g. You can’t implement the following collection accessors on AS objects as there’s no way to tell ASOC that the index arguments as unsigned ints, not object pointers:


- (void) insertObject:(id) obj in<Key>AtIndex: (unsigned int) index;
- (void) removeObjectFrom<Key>AtIndex: (unsigned int) index;

ASOC is arguably the one Cocoa technology where the AS team have done a half-decent job (since they did the sensible thing for once and copied from existing proven solutions), but it still has multiple dumb shortcomings and warts that with a little more care and thought could have been avoided entirely.

These sorts of faults not only limit ASOC’s usefulness, they also imply a lack of joined-up thinking and attention to detail that have other consequences too. Breaking polymorphism - a fundamental characteristic of OOP - hardly inspires confidence in ASOC’s general competence. Your average AS tinkerer may not realize these problems exist unless they fall right over them, but professional programmers who know their stuff and know what to look for when determining if an API is fit for use. Shoddy doesn’t just affect usability, it makes bad PR as well.