Penmanship and programming education (2016)
macwright.org
macwright.org
Yet only things called Lisp ever get flamed for this.
If it is just )))))) you only have to just auto-repeat ) until the editor indicates a match to the one you are trying to close. It's only "how many you owe", not "what kinds do you owe, in what order".
Why are we editing AST's like this!?
Clojure, in my opinion, did this right. You don't need very many alternate delimiters to get a lot of bang for the buck and break things up.
This is solved by "jump to matching", which every worthwhile editor I've used has had.
Example. I have this, in the middle of a larger body of code with more open parentheses which are not shown:
(foo (((((bar) ...
.....)) <-
Suppose that the point indicated by the arrow, I want to close (foo, and only (foo. Perhaps I want to start another unit that is on the same level of nesting as foo: (foo (((((bar) ...
)) <- must close this
;; (bar ... <-- want to start this; doesn't exist yet
So I just type ), or even auto-repeat. The jump-to-matching feature jumps backwards onto various parentheses that I don't care about, getting closer and closer to (foo. That (foo is where my eyes are; I stop when I see the backward jump hit (foo. If I overshoot, then I just backspace. Any good jump-to-matching feature works when you backspace to a parenthesis, not only when you type a new one. So after an overshoot, I can still keep my eyes on the (foo and backspace until the cursor jumps to (foo. It's like keeping your eye on the ball or other target in a sport.There is no value in knowing which of the other parentheses match which openers, and no value in having to interrupt the )))) to deal with other kinds parenthesis, when all I want is to close `(foo is a nuisance. That's just the down-side of whatever notational benefit those other kinds of parentheses bring.
When the cursor is on one delimiter, any decent editor should be able to indicate the corresponding delimiter, and allow you to jump to it if you want. So even if you have a screenful of parenthesis, there really should be no problem in figuring out which closing parenthesis corresponds to which opening parenthesis (or vice-versa).
Besides, as someone else pointed out, if you use something like paredit or smartparens, your parenthesis will always be balanced, so you'll never run in to this issue in the first place.
I myself made a dialect of Lisp in which there are square brackets too. They serve a very useful purpose. However, I wouldn't introduce this just for the sake of having a different character to match when closing. That aspect of it is undeniably a pain in the ass; I'm irritated by my own language when I have to close three parens, then close a square bracket and continue with parens. It's an irksome interruption that calls for my attention to the irrelevant, and I have to remind myself of the benefit of that square bracket.
It would be insane to introduce an alternative bracket which has to be matched with its mate, but is identical in meaning to the parenthesis, providing no semantic variation whatsoever. Nobody in their right mind would want to irk themselves on purpose with such a stupid thing.
Languages with syntax like end if and end while made a certain amount of sense in an era in which compiling your program meant standing in line with a deck of punched cards before a job submission window, and you needed to get as many diagnostics as possible out of a single run.
HTML's named closing delimiters for elements have a similar "benefit": the machine can keep going in the face of nesting errors and make some sort of sense of the document anyway. (The bad thing there being that the document is then effectively accepted as good.)
Clojure breaks readability for me personally, square brackets are a visual speed bump. And if different brackets improve things, Clojure should just use {} for blocks.
If you see { ... } or [ ... ] in CL code, someone tweaked the read table.
It's all great, and I too think paredit is great! But these are all techniques for improving the "writing new code" experience, which is the minority of work that anyone does. Nobody writes perfect code the first time. And these conveniences for writing new code don't help much with the majority of my time, which is spent editing, deleting, and refactoring code - and understanding at first glance the structure of a program from its punctuation.
So, sure - editors can do more and I'm hopeful about them. But I don't think that 'automatic bracket insertion' actually fixes this problem. I think it makes the task of writing code seem easier but doesn't help at all with the hard parts.
Instead of getting students comfortable with the syntax, I try to get students comfortable with syntax errors. Syntax errors are often trivial to fix after accumulating some experience; and as one gets experienced, they (syntax errors) tend to diminish anyway. However, the fear of syntax error -- just like the fear of water when learning to swim -- is very difficult to overcome and can be detrimental.
There is no logical reason to fear syntax errors, and there is no logical reason to worry about syntax when we are working with semantics.
Of course, we shouldn't accumulate syntax debt after hundreds of lines. We should organize our code into isolatable and testable units that fit into quick try/test and feedback cycles -- but that is common sense.
If my friend and I had worked harder at penmanship, and less hard at optional studies in AP/STEM stuff, we'd be less employable but would have scored better on the hand-written part of our placement tests. We both got a lot of grief in school from the traitionalists for our crappy hand writing. She still can't write cursive!
Before I became a programmer, I did Latin at school - the whold fiddliness of endings/cases was a great preparation. We frequently used terms for "syntax", "parse" and "[parse] tree" in class. This approach probably doesn't scale, but it worked really well for me.
Not sure if it was intentional, but I got a good giggle out of this line.