Wednesday, 1 April 2015

Marble and Wood

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