Others have written on the virtues of what we might call 'expressive terseness' in a language, which stems from the ability to do a lot with just a few operations. But another form of terseness whose virtues are more subtle is what we might call 'epigrammatic terseness' -- the ideal of having short, intelligible functions that only do one thing and do it perfectly. These two tend to go together insofar as expressive terseness facilitates epigrammatic terseness, but they're distinct insofar as you can fail to write epigrammatically in an expressively terse language (though you'd have to be stupid to do so) and can write epigrammatically in a non-terse language (though you'd have to be clever to do so).
'Functional style' tends to be epigrammatic by default, because only the value of the last expression in the function is ever returned -- so there's no point in cramming more than one expression into a function. This is one reason why it's nice to adhere to functional style even if you're writing in a language, like Common Lisp, that affords you all kinds of opportunities to violate that style with side-effects. Ideally, I try to segregate my programs into clean functional wings where all is carved in shiny marble, and dirty side-effect wings that are nailed together with planks of wood -- these wings adjoining each other but never overlapping. Admittedly it's a purely aesthetic preference: I just hate having to look at an ugly format expression on the same screen as a beautifully crafted lexical closure. But it helps keep my functions epigrammatic, which keeps them legible and memorable.
... and then I look at the macros, which are clearly all wood, and I think that perhaps the classical aesthetic enshrined in the marble wings is the one that's wrong. Most of the power of macros comes from their systematic violation of good functional style, and there is some deep wizardry available to anyone who's willing to do strange and unnatural things to their lexical closures. Macros at their best are all very wabi-sabi, which sits weirdly with the hygienic perfectionism of functional programming. This tension confuses me philosophically, but I appreciate the fact that CL is tolerant of both design attitudes.
Can you write good, clean code epigrams without the straightjacket of functional style? Yes, but further you depart from functional style and the more you embrace the intricacies of macros, the more the code starts to take on a queerly cryptic and holistic quality: the syntax tree of the individual expressions may be perfectly intelligible at a glance, but what semantics to assign it becomes unclear until you've figured out how all the bits splice together at runtime. Worse, deliberate ambiguities arise: the same unit of code may have a totally different interpretation when called in one context versus another. What is sacrificed is easy intelligibility; you have to feel your way into familiarity with the total codebase before it all starts to make sense. Manifest beauty gives way to what we might charitably call 'acquired taste', and code becomes profound and idiosyncratic.
I do not know if this left-hand path is good or not, but discovering that it's available at all poses a pretty firm challenge to my notions of good style. You have to be pretty smart to use it, and as someone who was attracted to Lisp because I'm a little stupid, it gives me a little frisson of numinous terror. And yet ...
'. . . one should only generalize in order to individualize better.' (Don Colacho)
Wednesday, 1 April 2015
Tuesday, 13 January 2015
Bash Considered Hopeless
In 'Bash Considered Pointless', Chad Perrin considers a few obvious points about bash:
1) That if you care about maximum portability across Unix-like systems, you shouldn't use bash. (Use sh.)
2) That if you care about maximum simplicity of code, you shouldn't use bash. (Use sh. Or better yet, rc!)
3) That if you care about maximum customizability of the shell environment, you shouldn't use bash. (Use zsh. Never use fish, however.)
4) That if you care about maximum performance, you shouldn't use bash. (Use (m)ksh or (d)ash.)
And given the recent discovery that there's been a veritable termite mound just underneath the floorboards of bash all this time, we can add: if you care about security, you shouldn't use bash.
That said, what principled reason could anyone possibly have to use bash? I can't think of any, which makes it look like a classic case of arbitrary market lockin -- somebody decided that bash was the standard shell for Linux distros, and bash is not so obviously awful as to foster great discontent among any but the most picky of operators. Until now, anyway: in light of the bashdoor discovery, there have been some murmurings that Fedora might move away from bash to mksh or dash, which would hopefully be the beginning of a stampede. One can dream, anyway.
Anyway, Chad makes another, more philosophical point that I find interesting: he thinks an interactive shell should be optimized to be an interactive shell and a programming language should be optimized to be a programming language, and that bash scripting falls rather inelegantly between these two stools -- or rather, is frequently abused to do things that should be done in a proper programming language. This point made me think of two things at once.
The first thing was Erik Naggum's infamous take on Perl: 'it's not that perl programmers are idiots, it's that the language rewards idiotic behavior'. But since Perl was pretty much made to 'correct' the deficiencies of shell scripting, it strikes me that all of Naggum's criticism applies in a suitably weaker form to that domain, as well. I don't have quite the same raging hate-on for Perl, but I see his point and think that any script that gets longer that a dozen lines or so should probably be redone in a proper programming language. It may in fact be a bad idea to make the shell too powerful, in which case anything more featureful than rc is probably harmful in the long run. (Seeing people seriously suggest patching bash with Perl is a confirmation of Naggum's worldview, and would be comical if it wasn't tragic.)
The second thing it made me think of is, of course, the Lisp REPL, which I think is a good counterexample to Chad's general thesis -- in an old Symbolics Lisp machine, there was no shell because there was no distinction between the command interface and the language the OS was written in. This strikes me as nirvana for the intelligent operator. Sadly, the last remnant of this principle still in use today is ... Emacs. Which, for other arbitrary historical reasons, is not a particularly inspiring exemplar.
In any case, please, whatever you do, stop using bash. Use zsh if you like big and baroque, use mksh/dash if you like small and snappy, or use sh/rc if you're truly hardcore. Just migrate to something else. Do it today. Do it now. You might like it!
1) That if you care about maximum portability across Unix-like systems, you shouldn't use bash. (Use sh.)
2) That if you care about maximum simplicity of code, you shouldn't use bash. (Use sh. Or better yet, rc!)
3) That if you care about maximum customizability of the shell environment, you shouldn't use bash. (Use zsh. Never use fish, however.)
4) That if you care about maximum performance, you shouldn't use bash. (Use (m)ksh or (d)ash.)
And given the recent discovery that there's been a veritable termite mound just underneath the floorboards of bash all this time, we can add: if you care about security, you shouldn't use bash.
That said, what principled reason could anyone possibly have to use bash? I can't think of any, which makes it look like a classic case of arbitrary market lockin -- somebody decided that bash was the standard shell for Linux distros, and bash is not so obviously awful as to foster great discontent among any but the most picky of operators. Until now, anyway: in light of the bashdoor discovery, there have been some murmurings that Fedora might move away from bash to mksh or dash, which would hopefully be the beginning of a stampede. One can dream, anyway.
Anyway, Chad makes another, more philosophical point that I find interesting: he thinks an interactive shell should be optimized to be an interactive shell and a programming language should be optimized to be a programming language, and that bash scripting falls rather inelegantly between these two stools -- or rather, is frequently abused to do things that should be done in a proper programming language. This point made me think of two things at once.
The first thing was Erik Naggum's infamous take on Perl: 'it's not that perl programmers are idiots, it's that the language rewards idiotic behavior'. But since Perl was pretty much made to 'correct' the deficiencies of shell scripting, it strikes me that all of Naggum's criticism applies in a suitably weaker form to that domain, as well. I don't have quite the same raging hate-on for Perl, but I see his point and think that any script that gets longer that a dozen lines or so should probably be redone in a proper programming language. It may in fact be a bad idea to make the shell too powerful, in which case anything more featureful than rc is probably harmful in the long run. (Seeing people seriously suggest patching bash with Perl is a confirmation of Naggum's worldview, and would be comical if it wasn't tragic.)
The second thing it made me think of is, of course, the Lisp REPL, which I think is a good counterexample to Chad's general thesis -- in an old Symbolics Lisp machine, there was no shell because there was no distinction between the command interface and the language the OS was written in. This strikes me as nirvana for the intelligent operator. Sadly, the last remnant of this principle still in use today is ... Emacs. Which, for other arbitrary historical reasons, is not a particularly inspiring exemplar.
In any case, please, whatever you do, stop using bash. Use zsh if you like big and baroque, use mksh/dash if you like small and snappy, or use sh/rc if you're truly hardcore. Just migrate to something else. Do it today. Do it now. You might like it!
Subscribe to:
Posts (Atom)