How Knuth Brushes His Teeth
A premature optimization?
Q: Do you have any other insights to offer into how you use maths in your work?
A: For instance, when I brush my teeth I’ve got eight areas to cover, namely Left and right, upper and lower, inside and outside. It’s most efficient to follow a “Hamiltonian path” or “Gray code”:
- left upper outside
- right upper outside
- right upper inside
- left upper inside
- left lower inside
- right lower inside
- right lower outside
- left lower outside
AppleScript Tips for Shell Scripting
OS X is surprisingly scriptable, including OS X applications. (Especially Apple’s applications). This is the good news. The bad news is that said scripts are difficult to write and debug, and they don’t play very well with Unix-style shell scripts. (Manipulating Unix-style filenames is especially painful.)
Here’s an example of what can be done:
select works like
open except that it opens a Finder window with the arguments selected:
The AppleScript code is complicated and involves far more workarounds than it really should but, hey, it does work.
Some tips and tricks in no particular order.
&for string concatenation:
return "Hello, " & name
as [type]to coerce to a string (you’ll need this for sane debugging):
return foo as stringwould be written in C-like languages as
return (string) foo
- Built-in properties can contain spaces:
track number of current trackis equivalent to something like
- AppleScript tries to be English-like (never a good idea): assignment is via
set foo to bar(not
set foo = bar) and you see things like
count of every media item of container src
log to dump output for debugging, though note that some types are coerced into strings for output–compare the output of
log obj and
log class of obj if not sure.
osascript’s error messages are pretty awful; for a slightly (slightly!) better development experience, use the Script Editor application. This gets you syntax highlighting, and slightly better
For best results click on the “page” icon in the bottom of the window to reveal the “messages” tab:
(Unfortunately Script Editor can’t open files that start with a shebang (see below)–you’ll need to copy and paste AppleScript to and from a text editor into Script Editor.)
There’s a few different ways you can run AppleScript from the command line. First of all, you can use the standard
#! shebang with
osascript as the interpreter:
To read arguments, use the
You might often find that you often want to do some pre-processing via
bash, especially for anything that involves filenames. This can be achieved (as in the
select example) via a
Use Script Editor’s “File | Open Dictionary…” to figure out what different applications let you do via AppleScript. Apple applications often expose a reasonably large API; for others you might get something minimal, or even nothing at all.
Spotify, for example, only lets you play/pause/next/prev. You can also get some information about the currently-playing track. One the other hand Apple Photos has a fairly rich API. (Example script.)
Working with filenames
Need the current working directory?
set pwd to do shell script "pwd"
Create file object from Unix-style path (with “/”):
(POSIX file unixpath)
Get Unix-style path from a file object:
(POSIX path file)
For more information on handling filenames, see:
Tabs and Makefile
The computing world is littered with unfortunate mistakes that managed to make the leap from small-scale inconvenience to a source of grief to millions or billions–at which point so many people and systems have been become accustomed to the error that fixing it is impossible.
One notorious example is the spelling of HTTP header
referer, which escaped the Netscape Corporation embedded in the bowels of their web browser without anyone noticing the error. From there it spread to every other web browser (they needed to be compatible), and finally RFC1945, the Hypertext Transfer Protocol standard itself. (At least, I’m pretty sure how things happened, but Wikipedia is inconclusive. Does anyone know?)
Another is the fateful decision of the author of
make to have the space character and the (visually identical) tab character do very different things. Very early on, the story goes, the author realized that this was a mistake, but by that point dozens of people were relying on it—backward-compatibility needed to be preserved—and so the tabs had to stay.
Unfortunately I couldn’t find a good source for this story online, so I emailed the author, Stuart Feldman, and asked him if it was true.
From: Michael Stillwell <...@google.com> Date: Mon, 20 Apr 2015 at 15:33 Subject: make versus tabs To: Stuart Feldman <...@google.com> Once upon a time I heard a story that soon after make was released, one of its first users complained that the requirement that each command line begin with a tab was suboptimal, and that some alternative approach should be used. As the story goes, the author was receptive to this criticism, but explained that sadly it was now too late to change the way things worked, because too many people were used to current behavior. The punchline, of course, was that at this point make had perhaps dozens of users. I was Googling a bit to try and figure out whether my memory was correct (it's surprisingly resistant to search), when I discovered that make's author works at Google, and so it might be possible to get a definitive answer by emailing you directly. So, to satisfy my curiosity, perhaps you could tell me: is the story true? Are there any other details you can recall and share? And how do you feel about tabs versus spaces versus whitespace now?
From: Stuart Feldman <...@google.com> Date: Mon, 20 Apr 2015 at 15:51 Subject: Re: make versus tabs To: Michael Stillwell <...@google.com> Story is only partly true. I used tabs because I was trying to use Lex (still in first version) and had trouble with some other patterns. (Make was written over a weekend, rewritten the next weekend ...) So I gave up on being smart and just used a fixed pattern (^\t) to indicate rules. Within a few weeks of writing Make, I already had a dozen friends who were using it. So even though I knew that "tab in column 1" was a bad idea, I didn't want to disrupt my user base. So instead I wrought havoc on tens of millions. I have used that example in software engineering lectures. Side note: I was awarded the ACM Software Systems Award for Make a decade ago. In my one minute talk on stage, I began "I would like to apologize". The audience then split in two - half started laughing, the other half looked at the laughers. A perfect bipartite graph of programmers and non-programmers.
Old Code & Large Numbers
Found an old passive aggressive (or maybe just aggressive) letter of mine that was published in an Australian science magazine for teens called Double Helix.
Horrible photo. It includes code, in BASIC. Numbered lines. There is a “clear screen” command though I seem to have avoided
Not really related, but while looking through Wikipedia for more information on this problem (it’s an an example of a Tag System), I came across some fascinating examples of conjectures that have extremely large (numeric) counter-examples. (i.e. conjectures resistant to computer-derived counter-examples, and common sense.)
- Pólya conjecture - initial counterexample was 1.845 × 10361, though now reduced to 906,150,257.
- Mertens conjecture - upper bound is e1.59×1040.
- Skewes’ number - somewhere around e727.95133.
Scott Aaronson has an intriguing blog post on the biggest number you can write down in 15 seconds using standard math notation.
See also Graham’s number.
.then() structures often recall async “callback hell”, there’s no consistency to APIs that return promises, and there’s no design patterns to introduce some order. (If working with push notifications, for example, you’re likely to end up with at least three Promise-returning constructions: a static property (
.ready), a getter (
.getSubscription()) and a verb (
One approach to improving this situation is to lean on ES6’s
yield or ES7’s
Use the same name for the promise and the name of the value the promise resolves to
Since you never really need the promise and the value the promise resolves to at the same time, give them the same name–they represent the same thing anyway, and giving them completely separate names makes no sense. (Annotating the types Hungarian-notation style might help, but it turns out that prepending or appending
promise to variable names looks silly.)
That is, if your promise is
foo, then the name of the argument should also be
Similarly, a function like
fetch() does not return a
fetchPromise; it returns a
Eliminate Promise chaining with functions, objects–any which way you can
Promise hell usually isn’t quite as bad as callback hell, but it can certainly be hell-ish. For example, some Promise-based APIs you may be able to encapsulate common operations on a
Separate Promise code from non-Promise code
A lot of code mixes together logic and the boilerplate that goes with the Promise syntax. Try to avoid mixing the two by moving all the boilerplate somewhere else. (Encapsulating it inside an object might a viable choice.)
It’s possible that it will help to convert simple values into Promises:
Try to write the code you’d write if Promises were built in to the language
When working with Promises, try to imagine what the code would look like if Promises were built in to the language as first class values. (That is, if you could use Promises wherever you would otherwise use values.) Is it possible to actually write code like this, by moving move the Promise-manipulation code somewhere else? If this is possible, is it otherwise a good idea?
printf-style debugging of Promises
Here’s a simple function for
console.log-style debugging of Promises:
Use it like this:
.then() lambdas can return promises
Resolving a list of promises to arguments
Remember that you can attache multiple “listeners” to a Promise