This is still the header! Main site

Syntax is Overrated

2021/10/25

... OK this might be somewhat controversial.

This is post no. 39 for Kev Quirk's #100DaysToOffload challenge. The point is to write many things, not to write good ones. Please adjust quality expectations accordingly :)

You might have encountered AppleScript at some point. It looks like this:


display alert "Hello, world!" buttons {"Rudely decline", "Happily accept"}
set theAnswer to button returned of the result
if theAnswer is "Happily accept" then
	beep 5
else
	say "Piffle!"
end if
          

It looks like this so that it's... kind of readable to users who aren't familiar with any programming language. On the other hand... it's kind of in an uncanny valley: generally, people don't normally say things like "set answer to button returned of the result" in English, so you do need a mental model of what's going on anyway. At which point... you might just be writing a more obscure-looking programming language, too: using various sorts of parentheses, brackets and such will make things actually more readable.

Furthermore... you have all this special syntax for alert buttons? and to display stuff? What if I want to, like, print text, with similar syntax, but no one has thought of adding fancy syntax for it?

Now... if you have seen too much Lisp... basically every other programming language start feeling like this.

A weird code example

OK so... let's take a look at this code.

fun makeNewPost(post_title):
   mkdir post_title
   new_post_file = concat
                post_title.asDirectory()
               "index.html"
   copyFile concat
                "..".asDirectory()
                "article_template.html"
               new_post_file
   findFile new_post_file
          

So... what programming language do you think this is?

Well, it kinda... looks like Python to me, with all the indentation, except... with fewer parentheses. Just by looking at though, you can kinda guess how "concat" is supposed to take the stuff that's indented under it as arguments. Nothing drastically new here.

And then... look at this...

(defun ssafar-make-new-post (post-title)
  (interactive "MPost dir name: ")
  (mkdir post-title)
  (let ((new-post-file (concat
               (file-name-as-directory post-title)
               "index.html")))
    (copy-file (concat
                (file-name-as-directory "..")
                "article_template.html")
               new-post-file)
    (find-file new-post-file)))
          

This is some horrifying, inpenetrable Emacs Lisp code. Just look at all the parentheses! Who the hell can figure out which goes where? How do they even count all of them?

Except... all I've done was replace the parens with spaces, "let" with an appropriately infix "=" operator, "file-name-as-directory" is now swapped around and pretends to be a string member function... really not a lot more. (Ohh also, I removed "interactive" to make it a tiny bit less obvious that this is Emacs Lisp.)

Once you get used to it, you don't even see the parentheses. Just like you kinda ignore e.g. Java's curly brackets as background noise and look at indentation instead, you can still figure out what's happening without them. Python's big insight was that you can use actual whitespace to do this. Lisp doesn't make all the parens transparent... but they could just as well be.

Ohh and if you're using the right editor, it's actually impossible to write unpaired parens.

So what's the point of syntax anyway?

Before this turns too much into a "Lisp is Great" article... let's return to the main point. Namely... why do programming languages... or natural languages, for that matter... even have fancy grammar and rules and fixed constructs?

I think it's actually a tradeoff. What you want to forward, regardless of whether it's a sentence or a function definition, is a tree. The other side will parse it into a tree eventually anyway. However, given how humans are basically thinking meat who make meat noises at each other to communicate in a sequential way, we had to come up with rules to turn trees into strings of sounds (or characters) so that we can parse them back. Thus, grammar rules.

With programming languages, we continued the same tradition: aren't programs just verbal instructions for computers to follow, after all? But then... we wanted our trees back. Computers were a whole lot more stupid than humans though, so we just inserted the minimum amount of parentheses, brackets and punctuation to make it more obvious to computers how to parse the text in question.

Want to make it human-like? Remove punctuation, add grammar. (You get AppleScript.)

Are we okay with some weird characters? OK, there you go: C, Java, Python.

Lisp just... went all the way. No smartness assumed on the computer's part: we're making it really stupidly obvious how to make a tree out of this. This is the reason why you can write a Lisp parser / reader in an afternoon. Try doing the same, with, um, C++.

The counterpoint to "Lisp is Great"

Most Lisp people will not fail to let you know that it's a lot better than everything else because data looks the same as code, so you can generate code more easily, etc etc. Look up "homomorphism" if you'd like to hear more of that side of the argument. As in: by making things ugly and full of parens, we gain awesome Lisp powers.

My point here is pretty much the other side of this: by making things clean-looking and having fewer parens, things are... not that much better.

We're really not saving a lot by letting you skip writing a few parentheses and using symbols to abbreviate some words. Both are similarly easy to read if you indent them correctly (... and both are unreadable if you don't... unless it's Python, which made bad indentation conveniently impossible). Sometimes, you have to swap around some words (in a method call on an object, does the object or the method name come first?), but... mostly that's it.

And for all this, we're giving away simplicity, introducing a rigid, hard to extend, fused-into-the-compiler parser, generating a fairly ugly abstract syntax tree, which is ugly enough that it's not even exposed to users. As a result, adding a foreach loop construct is now a committee decision. (With Lisp, you can come up with and add a new kind of loop syntax in about 5 minutes.)

Which... would be a worthy tradeoff if non-Lisp languages were so much more easy to read, or to write. I'd argue that they aren't though, once you get used to not noticing all the parentheses.

Counterexample!!!

Before concluding that Lisp Is Always Better, here is an example where it is not:

HTML.

... or XML, Markdown or similar formats designed to hold both text (... which is not a tree to be parsed by computers) and formatting info (which... makes it technically a tree, but that's actually not the important part). Having to quote every single string part separately as a Lisp expression is definitely not a fun way of writing blog posts.

... comments welcome, either in email or on the (eventual) Mastodon post on Fosstodon.