Re: JavaScript for automations: bug or correct behavior
Re: JavaScript for automations: bug or correct behavior
- Subject: Re: JavaScript for automations: bug or correct behavior
- From: has <email@hidden>
- Date: Tue, 20 Jan 2015 23:42:25 +0000
On 20/01/2015 21:18, Alex Zavatone wrote:
Has, nice observation on the returning 0 in one case and returning 1 in the other. Eeeegg.
Regarding your support and documentation of an AE bridge, which AE bridge are you talking about? I'm rather clueless in that respect.
I wrote appscript, which eventually appeared in Python, Ruby, MacRuby,
and ObjC flavors until I finally pulled the plug in 2012 due to
completely buggering up on the logistics. [0] I also wrote a
JavaScriptOSA component last year (no relation to Late Night Software's
long-deceased OSA component of the same name), which included an
appscript-style Apple event bridge.
Other Apple event bridges of particular notoriety are 10.5's Scripting
Bridge framework, the AE bridge included in 10.10's JavaScript for
Automation OSA component, and, of course, AppleScript's own built-in AE
bridge, which is also the de facto standard against which every
scriptable app of the last 20 years has been developed and tested, and
most heavily used.
And then there's the various other third-party attempts from over the
years: Userland's Frontier (which provided both AE and OSA support, and
predated even AppleScript), Perl's Mac::Glue, Python's
gensuitemodule+aetools, Bill Fancher's OSAPython, Bob Ippolito's aeve
(Python again), LNS's JavaScriptOSA, Laurent Sansonetti's RubyOSA (AE
bridge-only, despite the name), and there might even be one or two
others that I've forgotten, or aren't even aware of.
Ah well, in for a penny, in for a pound. Learning moment ahead. Be warned...
Apple events use 1-indexing natively (for by-index specifiers and AEList
descriptors).
All "scriptable" (i.e. Apple event-aware) apps respect AEs' 1-indexing
semantics.
The AppleScript language uses 1-indexing natively (for AS list items).
AppleScript's own Apple event bridge preserves AEs' 1-indexing
semantics; that AEs and AS semantics just happen to be identical here
is, shall we say, "convenient". [1]
So far, so good. The headaches begin when you try to bridge Apple events
to a 0-indexed language such as C/ObjC, Python, Ruby, JavaScript, etc.
Now your bridge is faced with an impedance mismatch between the native
AE semantics (1-indexed) and the native language semantics (0-indexed),
and there's only two possible ways it can deal with that:
1. Deal with the mismatch itself (by adding/subtracting 1 to/from index
numbers in various places).
2. Drop the whole mess onto the user and leave them to deal with it.
On the face of it, #1 is the clear choice: hide all the complexity and
work of dealing with such mismatches within the bridge so that the user
never has to know about or deal with it. So the bridge developer
scurries off and implements that, and - Yay! - users' lives are made
simple and easy, because Everything Just Works exactly as they'd expect.
Of course, if you believe that then I have a bridge to sell you. Joel
Spolsky coined a great term for the actual reality: the "leaky
abstraction" [2].
Or, if you prefer my own more localized, profane version:
"The AppleScript universe *hates* smartasses and *always* kicks
their butts."
Both of which are just variations on the old "your sin will find you
out" admonishment, of course.
Basically, trying to resolve such mismatches internally works, but only
up to a point. Beyond that point it starts to break down, and frequently
breaks hard - because not only is the technology itself broken but also
all of the users' previous understanding and confidence in it. It's one
of the lessons I learned during my first year on appscript (versions
0.5.x and earlier). Initially I did the 0-indexing thing because it was
what Pythonistas were used to but, as myself and others started using it
for real work, the leaks began to spring.
For instance, did you know that FileMaker used index 0 to specify a
special table? Since early appscript "corrected" index number 0 to index
number 1, it could never construct specifiers for table 0 so its
FileMaker compatibility was broken. Don't recall if it was Derp #1
("Derp #0"?), but it was certainly one of the first gotchas I ran afoul
of in trying to "Pythonize" Apple event semantics. And, needless to say,
it would not be the only one.
Things got worse as I built out support for more complex reference
forms. While 0-indexing mostly worked in single-element by-index
specifiers, when it came to by-range specifiers I had a nasty
realization: while AE and AS element ranges were fully inclusive, Python
ranges were not:
text 2 thru 5 of "ABCDEF" --> "BCDE"
"ABCDEF"[2:5] --> "BCD", i.e. the last index is *not* included!
So I tried to compensate for that too by adjusting the end index number
up and down as appropriate. Now you could write:
app('TextEdit').documents[0].text.characters[2:5].get()
and it'd return characters 2, 3, and 4 as Python users would expect.
Then I tried to figure out how to make the same trick work when the
by-range specifier contained more complex start/end values: element
names, relative specifiers, etc. For example, should the following
specifier include the Movies folder or exclude it?
app('Finder').home.folders['Documents':'Movies']
And how should it deal with the following:
app('Address
Book').people[0:con.people[its.last_name.starts_with('P')]]
Obviously, the bridge can't just add and subtract 1 any more. It could
always append a `previous <element>` selector to the existing specifier
so that, e.g., con.folders['Movies'] automatically converts to
`con.folders['Movies'].previous(k.folder)` before being sent to the app.
But what should it do when the app decides that this query is just too
complicated for its poor little brain and throws back an error? And what
about the user? She *knows* this query should work, because she's
already tried it in AppleScript, and now the bridge is not only throwing
back an error message but also the message itself is describing a
specifier that looks nothing like the one she actually wrote.
The more I tried to make appscript more "intelligent" and "helpful" by
layering on more and more of these "clever" abstractions, the more
complicated, slow, and brittle it became; and still fresh leaks would
spring. And, of course, being a dumbass I spent a whole year falling
down that rabbit hole before *finally* going "WTF?!?!?", throwing out
the whole lot, and redesigning and rewriting it from scratch (appscript
0.6+). And it's not like I hadn't studied all the successful and
unsuccessful AE bridges that had already been developed by other much
smarter, skilled programmers than myself. (Heck, even the mighty Mark
Aldritt managed to botch his own JavaScriptOSA implementation in several
excitingly creative ways.)
Honestly, excessively clever software will be the doom of us all.
In the end, the only approach *proven* to work is that already used by
AppleScript's own AE bridge: expose Apple events' own semantics directly
to the user, and carefully apply light touches of syntactic sugar to
make it more pleasant to use *only* where it won't create any confusion
[3] or compatibility problems. So I replicated that and - presto - a
couple weeks of coding and a couple years of field-testing and debugging
later, one proven industrial-strength Python-to-Apple-event bridge
served. Everything else then becomes an education problem, and full
documentation and diligent user support goes a heckuva long way to
solving that.
But you try telling that to the young programmers of today... they won't
believe you.
HTH
has
[0] Failed to get appscript into 10.5; failed to influence the design of
10.5's Scripting Bridge so that it wouldn't suck donkey nuts; could see
the writing on the wall for the Carbon APIs on which it depended, and
suspected AppleScript might not be around too many more years either.
Never let it be said I don't suck too.
[1] To be fair, the Apple Event Manager was designed back when Pascal,
which also used 1-indexing, was still commonly used for Mac development.
So it's more likely the AEM was initially designed to be
Pascal-friendly, and AppleScript just happened to luck out as a result
of that.
[2] See <http://www.joelonsoftware.com/Articles/LeakyAbstractions.html>
for Joel's original article, or the dread Wikipedia for the short
version <http://en.wikipedia.org/wiki/Leaky_abstraction>.
[3] Yes, well, even AppleScript's not perfect on that score. (Implicit
"get", anyone?) But that's why the final appscript design makes even
AppleScript look like some whacked-out hippie liberal by comparison.
Appscript's what turned me from the wildly reckless cowboy coder of
yesteryear to the ragingly conservative cowboy coder of today - Thanks,
AppleScript!
_______________________________________________
Do not post admin requests to the list. They will be ignored.
AppleScript-Users mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
Archives: http://lists.apple.com/archives/applescript-users
This email sent to email@hidden