Re: functions as sort of first class objects
Re: functions as sort of first class objects
- Subject: Re: functions as sort of first class objects
- From: has <email@hidden>
- Date: Fri, 27 May 2016 16:38:41 +0100
Mitchell L Model <email@hidden> wrote:
>> > On May 26, 2016, at 3:00 PM , has <email@hidden
<mailto:email@hidden>> wrote:
>> > Subject: Re: functions as sort of first class objects
> I thank you I thank I thank you. That is one of the most — possibly
the most — informed, clear, instructive, and helpful descriptions I’ve
seen anywhere about all the topics you mentioned. [...] I have never
understood the purpose or applicability of script objects and
inheritance in AppleScr
If you know OOP then script objects and their delegation-based
inheritance are what allow you to do a form of protoype-based OOP[1] in
AS, should you ever build anything sufficiently complicated to need it.
Unlike Smalltalk, Python, etc, AppleScript doesn't have 'classes', so
there's no 'class vs instance' dichotomy: everything is just objects.
Closest familiar OOP analog is JavaScript, although it does *everything*
by chaining new objects to existing objects - 'cloning' in JS merely
creates creates a new _empty_ object that delegates to the 'cloned'
object; there's no actual object copying as the term 'clone' might
imply. OTOH, AS _can_ literally clone script objects using its built-in
`copy X to Y` statement, but that performs an excessively deep copy that
duplicates absolutely everything in the delegate chain, up to your
top-level script and _everything_ in that, which unsurprisingly causes
everything to bog down and break incredibly fast; so never do that.
Instead, use a handler to construct new script objects by executing a
`script...end script` statement:
to makeWelcomingObject(salutationPhrase)
script WelcomeObject
to doWelcome(userName)
say (salutationPhrase & space & userName
end doWelcome
end script
end makeWelcomingObject
set politeGreeting to makeWelcomingObject("Greetings")
set casualGreeting to makeWelcomingObject("Hiya")
politeGreeting's doWelcome("Bob") -- says "Greetings Bob"
politeGreeting's doWelcome("Sue") -- says "Greetings Sue"
casualGreeting's doWelcome("Bob") -- says "Hiya Bob"
Oh, you'll note in the above that the script object provides
closure-style behavior, capturing the scope in which it was created (the
`makeWelcomingObject` handler's stack frame). Which is another reason
for never trying to treat handlers as native objects, because handlers
aren't closures so any free variables they contain will break horribly
and in completely bizarre and unpredictable ways the moment the handler
'object' moves to a different scope.
Script objects also provide the foundation for implementing library
systems (e.g. my old AppleMods loader and AS's own 10.9+ library
loader). And, of course, every script you write and run compiles into a
script object, which can be serialized for storage to disk (or to send
over IPC) and deserialized into a fresh script instance, so they're the
foundation for AS's automatic, [almost] ubiquitous state persistence
system as well (another Smalltalk influence, albeit on much smaller
scale than mighty Smalltalk VMs). While not without its own shortcoming
and defects they're actually one of AS's better ideas: just compare the
mess of complexity in something like Python, which has 'class' objects
and 'instance' objects and 'module' objects, and no intrinsic mechanism
for persisting script state between runs. (Needless to say, I'm not at
all shy about ripping off AS's best ideas for use in my own libraries
and languages; and, of course, what NOT to replicate on pain of death.)
> It’s very difficult identifying undefined behavior in AppleScript,
because everything in it is so weird that most of the time I either
reuse and modify pieces of code that worked in another context or wander
around until I get something working.
If a feature isn't listed in the official documentation (ASLG), then
it's undefined.
Of course, even when a feature IS listed in the ASLG, there's absolutely
no guarantee that the ASLG isn't lying its face off about what it
actually is and how it really works. The AppleScript language lies like
a pig in shit: all with the very best motives, of course - being simple
and friendly and easy to use - but the problem is the language itself is
actually heinously complex, and the right way to make a language simple
and easy to use is to *eliminate* that complexity completely, not
pretend to users that it doesn't exist.
For instance, ASLG never tells you that all the Apple event IPC stuff is
actually RPC plus simple first-class relational *queries*[2], which is
why 99.9999% of programmers absolutely despise and cannot understand AS:
because AS syntax looks just enough like OOP that they naturally assume
that's what it is, so are utterly flummoxed when it ups and does
something utterly NON-OOPish on them. (And don't expect this ever to
improve, because the AS team has repeatedly demonstrated that its answer
to programmers failure to like, use, or support AS is to LIE EVEN HARDER
TO THEM.)
Though to be fair to the original AS designers, some of the crap in AS
is the unfortunate consequence of Apple mgt scrapping the original AS
team the moment 1.1 went out the door, which meant a lot of problems
that might've been identified and fixed early on never were; while other
problems (e.g. the atrocious mess that is file paths and file
system-related types and specifiers: alias, POSIX file, etc) are the
unhappy result of trying to update or supersede original language
features hamstrung by the technical limitations of System 7 without
breaking existing code compatibility. (Particularly when the new
additions aren't as rigorously thought through as they could be.) A lot
of it though is just what you'd expect when programmers try to spelunk a
previously unexplored and unfamiliar field in language design, and maybe
don't have quite as wide a perspective on the topic (End-User
Programming) as they really ought to.[3]
> In the process, unfortunately, as often happens with that kind of
approach, is that I’ve built up mythical beliefs as well as kept mental
pictures of things that have changed since I made them. One of the
contributing factors is the minimalist approach the AppleScript
documentation takes, though for what it is trying to do is actually very
good. I think I read every AppleScript book that’d been published before
about 8 years ago, but I don’t think any of them went into much
sophisticated detail.
Your best bet is Apress's Learn AppleScript, 3rd edition, which I
lead-authored. It still doesn't get into a lot of the really deep
conceptual and technical stuff: I didn't say anything about application
scripting being RPC+queries, for example, because the audience was wide
and you gotta pick your battles. But one of the things I did include was
a chapter about using script objects for doing libraries and OOP; the
library stuff is pretty useless now that AS has its own native loader,
but the OO stuff holds up (caveat a couple embarrassing errata, which
I've already asked Apress to put on their site and they failed to do so,
but I can email as a plain text file directly on request).
> What led to attempt this weird first-class object sort of thing — and
gee, isn’t that what a script object is, duh? — is that I wanted to
write a set of unit tests drive by a harness. Something like:
Been there, done that:
https://github.com/hhas/applescript-stdlib
I've been remiss in getting that particular project finished off and
properly distributed[4], plus the TestTools harness just happens to
tickle a really wonderfully bizarre and utterly unpredictable bug deep
deep in the AS implementation that periodically causes test scripts to
fail in all kinds of really wonderfully bizarre and utterly
unpredictable ways until you change a couple of characters at which
point they suddenly magically work perfectly well, at least until the
next code edit you make happens to set that damn bug off again. So if
you want to write unit tests I recommend you just use that, and then
slam me for inadequate documentation and examples till I motivate my
lazy ass to fill in the remaining gaps.
> I realize this is pushing AppleScript a bit, but I was curious to see
if it could be done.
Not at all. The language may suck, but it's "Turing-complete" as all the
cool kids love to say about things[5], so you can write anything in it
as long as you don't need to dive down to raw C calls to interact with
external stuff, cos its FFI is various degree of limitations and suck.
And don't mind it running slow as molasses, or falling down on stupid AS
bugs, or generally drive you up the wall by being stupidly limiting and
obtuse in how it lets you do it. e.g One time someone asked about
writing a calculator in AppleScript
<http://stackoverflow.com/questions/35538631/eliminate-hyphen-from-applescripts-text-item-delimiters/35539918#35539918>,
and I obliged them.:) I just wouldn't _recommend_ it where you can help
it: cos while all languages may be crap, using one that's even
marginally less crap than AS will still save you a huge amount of time
and frustration. Stick to using AS for desktop automation - which is the
one thing it actually does right (and all the other official
'alternatives' do wrong) - and while you won't avoid pain at least you
won't inflict even more than actually necessary.
> Anyway, thanks again for your wonderful post. I will change my code
to use a script object forthwith.
>
> This came just in time, because I will be distributing the handlers
with their tests soon to the Keyboard Maestro forum — the handlers
actually call KM macros through KM’s AppleScript commands, so I can test
the KM macros from this AppleScript. Each test puts starting text in a
new TextEdit document, does stuff that involves calling one or more KM
macros, gets the text of the doc, and compares it to the expected text.
I will probably parameterize the initial text and expected resulting
text too.
Tests are good. We should do more of those (not least the AS team itself!).
HTH
has
--
[1] OOP's just another tool that helps you manage growing complexity by
organizing and packaging your code; basically the next step up from
using libraries, which are the next step up from using handlers. If all
your scripts are just quick 1-10 liners, of course, then it's not
something you're very likely to need, of course.
[2] I strongly recommend reading the following paper by one of the
original AS designers:
<http://www.cs.utexas.edu/users/wcook/Drafts/2006/ashopl.pdf>. And for a
more dev-friendly (albeit rough) summary of AE IPC:
<http://hhas.bitbucket.org/understanding-apple-events.html>.
[3] AppleScript was derived from HyperTalk, which in turn draws much
from Pascal because that was the standard teaching and production
language for programmers back then; whereas what HT really should've
been based on was Papert's Logo which, instead of trying to achieve
simplicity through great cleverness and hidden complexity, achieved
simplicity by _being simple_.
[4] Laziness, sickness, and the fact that this 'good deed' crap
invariably takes twice as long as intended and doesn't pay a dime so
real [potentially/actually] paying work needs to take priority. [6]
[5] Despite being neither old enough to have met a Turing Machine nor
even appreciate what the damn phrase truly means and how it really isn't
being helpful or meaningful at all.
[6] (Also the fact that having offered to turn the code over to Apple,
lock stock and barrel, totally gratis no strings attached, the AS team
can't even bother their asses to respond with so much as a "thanks but
no thanks". 'Cos nothing says "We want our Users to love and use
AppleScript" like an AppleScript team that gives every appearance of not
giving a shit about either. So sue me, it's not my professional job to
pick up after their crap.)
_______________________________________________
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