Scripting bridge: an API to run AppleScript
| Originator: | amorya | ||
| Number: | rdar://19396977 | Date Originated: | 07-Jan-2015 10:34 AM |
| Status: | Open | Resolved: | |
| Product: | OS X SDK | Product Version: | Mac OS X 10.10.1 (14B25) |
| Classification: | Enhancement | Reproducible: | Always |
Since the Scripting Bridge can never be perfect (purely by view of it being an abstraction on top of a poorly specified language that every target app implements differently), we need a way to drop down to AppleScript itself. Can I suggest something like the following: - [SBObject executeAppleScriptWithFormat:(NSString*)appleScript, …] What this would do is execute the piece of AppleScript as if it were inside a “tell ___” block, with ___ being the SBObject that it was sent to. (You’d need to be able to send it to an SBElementArray as well.) The format would be a string of AppleScript, with substitution variables which allow you to plug other SBObjects into there, and the Scripting Bridge figures out how to get the right AppleScript reference to the object and pass that in. So I’d be able to do something like this: OmniFocusContext *context = … OmniFocusTask *task = … [task executeAppleScriptWithFormat:@“set context to %@“, context]; Obviously the above is just an example, since that is something that could be done with the Scripting Bridge directly, but there will always be things that cannot be done, so we NEED a way to drop down to AppleScript itself.
Comments
Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!
this is a bad idea
It is true that Scripting Bridge can never be perfect, but that is ONLY because SB is deliberately, inherently defective by design.
Issue:
There is a significant impedance mismatch between Cocoa APIs, which are Object-Oriented, and Apple event IPC, which uses RPC + simple first-class relational queries. There are two possible ways to deal with this mismatch:
Present Apple events' straightforward - if unfamiliar - RPC+query semantics directly to the ObjC user, and teach them how to understand and use it correctly.
Hide those query semantics from the ObjC user beneath a thick ORM abstraction layer that pretends it's an OO API for manipulating proxy objects (c.f. Distributed Objects).
AppleScript, appscript, Frontier, and Mac::Glue took the query-builder approach. AppleScript is the de facto reference implementation against which all other AE bridges are measured. Appscript achieved approx. 99.9% application compatibility; or 99.999% if you also count the lower-level fallback APIs provided by its multi-layer architecture. Frontier was probably in the 97-99% range. Mac::Glue was hobbled in other ways by Perl's awkward syntax and limited type system, so was never a serious contender.
Gensuitemodule+aetools, aeve, OSAPython, RubyOSA, and Scripting Bridge attempted the ORM approach.[1] None of those ever worked right. AE semantics are a superset of OO semantics, so crippled functionality and broken compatibility is the inevitable outcome. Even ORMs for relational database applications fail to provide 100% compatibility when targeting a handful of relatively identical RDBMSes, and those are nothing compared to the vast number and variety of "AppleScriptable" desktop apps.
Solution:
Messing If you want ~100% application compatibility, the correct solution is to deprecate Scripting Bridge and introduce a new appscript-style framework - e.g. see https://bitbucket.org/hhas/appleeventbridge for an example - that has already been extensively field tested and proven itself fit for purpose.
An appscript-style architecture is multi-layered, providing multiple fallbacks in situations where application terminology is unavailable or broken; e.g. its lower-level AEM... classes use four-char codes (equivalent to using AppleScript's raw chevron syntax) where terminology is absent, while static glues allow individual terminology defects to be manually corrected. It also reduces initialization time to milliseconds; SB takes anything up to 10 seconds to initialize an SBApplication object, depending on size and complexity of app dictionary.
An appscript-style architecture is also extremely granular, allowing easy reuse of individual query-building and AEDesc pack/unpack classes alongside standard Cocoa classes such as NSAppleEventManager and NSAppleScript/OSAScript: no need for special "integration" to be welded in.
In other words, this issue is already fully solved in technical terms.
Conclusion:
The problem is in persuading Apple to incorporate such a solution into OS X, which is a logistical challenge. The current AppleScript team has repeatedly demonstrated they are unwilling and/or incapable of doing the job right themselves, and would inevitably lose face should their current APIs be junked. Plus there are other cost issues for both Apple and current API users when replacing APIs. Thus it would require significant political pressure from more senior and/or influential groups within Apple to override the AS team and force a correct solution upon them.
Perhaps if you can rally enough supporters inside and outside Apple it might become possible, although given how badly damaged AppleScript's reputation is and how little influence it holds now that OS X development is primarily directed by iOS and iCloud, it'll be an extremely hard sell.
However, botching AppleScript into SB and SB into AppleScript as a workaround for SB's inability to do its job right would be the worst of all "solutions", layering even more brain-hurting convolutions onto an already hideously screwed-up stack. Given the choice between that or doing nothing, I would strongly recommend the latter.
Failing that, I would recommend submitting as many duplicates as possible of http://openradar.appspot.com/radar?id=6142979584557056 and http://openradar.appspot.com/radar?id=5213982453399552 in order to add essential functionality to NSAppleEventDescriptor and correct a longstanding bug in OSACopyScriptingDefinitionFromURL. These fixes would allow app developers to bundle a third-party AppleEventBridge framework in their app instead of using ScriptingBridge, without being hobbled by AppStore incompatibilities or being critically dependent on legacy Carbon APIs of uncertain future. Still not ideal, but infinitely better than submitting hundreds of futile Radars on the SB itself.
--
[1] Late Night Software's JavaScriptOSA and Yosemite's JavaScript for Automation are both messy hybrids of both approaches: the underlying implementations correctly uses a query builder, but this is crippled by various pseudo-OO-isms layered on top.