Hacker News new | past | comments | ask | show | jobs | submit login
Penmanship and programming education (2016) (macwright.org)
34 points by dhotson on Sept 15, 2017 | hide | past | favorite | 22 comments



> }))}`] } }

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".


Lisp has a lot more of them. The same semantics expressed in Lisp will have a lot more grouping characters than in another language with a richer syntax and multiple levels of operator precedence. (The benefit in Lisp's case, of course, is that you don't need to know that richer syntax and precedence hierarchy.)


Not Common Lisp; just different openers: #( vector, #c( complex number, #s( struct, ... all close with ).

If you see { ... } or [ ... ] in CL code, someone tweaked the read table.


paredit.

Why are we editing AST's like this!?


Exactly. Whenever people talk about the specter of brackets, I feel like a Siberian hearing about global warming. With a properly-configured editor, brackets are a tool to improve code navigation.


Because, in Lisp, getting it wrong means that you don't know which one was supposed to close which opener. And which is a vector, which is a list, which is a hasmap, etc.

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.


There's no need to resort to Clojure to solve this.

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.


That's like not knowing which electron is supposed to flow through which resistor. Man, how do electronic engineers work without knowing important things?

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.)


> getting it wrong means that you don't know which one was supposed to close which opener

This is solved by "jump to matching", which every worthwhile editor I've used has had.


That causes the problem of knowing something you don't want to know. That problem, in turn, is solved by not looking at what "jump to matching" is specifically doing, other than watching for it hitting your "target parenthesis".

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.


If we don't know that, our code has worse problems. It's the same in C-syntax languages with an if in a for in a function inline in a class. Losing a } is the least of our problems.

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.


I don't use the "I owe a thing" method. I put the closing bracket/quote in when put the opening one in, and then hop left a space and fill in the content. I find it too confusing otherwise. For exactly the reason the author describes.


It must be that neither of you use an editor which knows how to match parentheses. Then the choice of habit is largely moot. Also, that little leftward jump can be automated by the editor, which is useful if you want it more often than not.


Agreed. And for that matter there is a tremendous amount of context a programmer must keep in her head. If your bracket stack is top of mind I fear for your users. I am a pedant at heart and have had many in depth conversations about semantic naming, structure and idiomatic code. But leave bracket matching to the IDE.


Author here. I've used plenty of editors that 'know' how to manage parenthesis. And editors that did even more than that, like auto-completing snippets and moving around the cursor.

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.


The idea that we need to get the code correct in one-go is questionable. Any coder only has limited slots for short-term memory. Spending some of those slots keeping track of syntax balancing is a questionable advice.

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.


Funny, but slighly off topic; I just had a long conversation about the opportunity cost of teaching penmanship in public schools.

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!


I mean I don't think being able to write in a way that can be read is some obscure, useless skill. I had to go through a lot of extra instruction in penmanship when I was a kid but it was totally worth it because a life where nobody could read anything I wrote would have been needlessly difficult.


> I think it’s time to give syntax and writing the time and respect it deserves.

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.


Related: Computation and State Machines by Leslie Lamport (https://www.microsoft.com/en-us/research/publication/computa...).


> Programming is relatively unforgiving

Not sure if it was intentional, but I got a good giggle out of this line.


I don't know you learn these things with practice. You practice when it's fun. But that part of programming is boring. Maybe some focus could be given but it sounds like it could suck the motivation out of would be programmers.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: