I wrote a nontrivial AppleScript to merge duplicates in my iTunes library.
It is easily the most gruesome thing I have ever written.
Some things of notes:
-
I had to write my own function to sort lists.
-
I had to write my own function to split strings.
-
AppleScript has records, which are like dictionaries, except they do not support dynamic properties. Consider that. You can do
{foo: 1}
to create something that is morally equivalent to{"foo": 1}
. But what do you do if you want to use a property name that's in a variable?In AppleScript, you cannot. You can only wail and gnash your teeth.
This lack of dynamic property access meant that I couldn't use records at all in my script, for which I suffered greatly.
-
There are vast numbers of predefined symbols with names that invariably conflict with your own variables and functions. Somehow, AppleScript appears to implement reverse lexical scoping, and these predefined symbols override your own.
-
On a Mac, there are a large number of characters that are easy to type with the option key. So, of course,
!=
,>=
, and<=
can be written as≠
,≥
, and≤
, and -
The inscrutable raw property accessor is written with
«class NAME»
. Yes, those are double chevrons. -
There is a line continuation character, but it is
¬
. (Option + L on a Mac keyboard.) -
Property access,
bar.foo
, can be written asfoo of bar
orbar's foo
. Except in some contexts, where onlyfoo of bar
is accepted. I have run into these contexts many times, but I am still unable to predict them. -
There are wholly optional keywords that can be used but do nothing. You can use the word
the
in front of any expression, which does nothing.set the x to the 1
is exactly the same asset x to 1
. -
There are multiple ways to do almost everything. For example, you can define a function with
to function(…)
oron function(…)
.
The language's smatterings of levity are, sadly, quickly overwhelmed by how dysfunction it is.
Here are actual snippets of actual code that I actually had to write:
set AppleScript's text item delimiters to d
set l to s's every text item
set i_track to (item i of l)'s track number
to trash_file(l)
do shell script "mv " & ¬
quoted form of POSIX path of (l as string) & ¬
" " ¬
& quoted form of POSIX path of (path to trash as string)
end
to cancel(m)
display dialog m
error number -128
end
set i to my split(f, ".")'s first item as number
if n's length ≠ o's length
if p's visible and ¬
p's special kind = none and ¬
not p's genius and ¬
not p's smart and ¬
index of last track of p < 1500
set normal to normal & {p}
end
set old_plays to old's «class pPlC»
delete (some track of library playlist 1 whose database ID is old_dbid)
repeat with i from 1 to count of n
set old to item i of o
set new to item i of n
set oldid to old's persistent ID
repeat with j from 1 to count of normal
set p to item j of normal
set ts to tracks of p
repeat with k from 1 to count of ts
set t to item k of ts
if t's persistent ID = oldid
delete t
duplicate new to p
end
end
end
end
This script should run instantly, but takes more than a minute when 10 tracks
are selected. This is because of the above triply nested repeat
loop, which
loops over all the tracks I want to merge, all the playlists in my music
library, and all the tracks in those playlists. I had to do it this way because
I don't have any form of random access or dictionaries.
Even though the script is pretty simple, it still fails nondeterministically. I am unable to determine what could make such a simple script fail, and nondeterministically at that.
If hell has a programming language, it is definitely AppleScript.