Express What, not How.

Brian McNamara! gt5163b at prism.gatech.edu
Tue Oct 14 22:52:41 EDT 2003


Raffael Cavallaro <raffaelcavallaro at junk.mail.me.not.mac.com> once said:
> Marcin 'Qrczak' Kowalczyk <qrczak at knm.org.pl> wrote:
>> Sometimes a function is so simple that its body is more clear than any
>> name. A name is an extra level of indirection. You must follow it to be
>> 100% sure what the function means, or to understand what does it really
>> mean that it does what it's named after.
>
>Your argument is based on the assumption that whenever people express 
>_what_ a function does, they do so badly, with an inappropriate name.
...
>Anonymous functions add no clarity except to our understaning of 
>_implementation_, i.e., _how_ not _what_. Higher level abstractions 
>should express _what_. Implementation details should remain separate, 
>both for clarity of exposition, and for maintanence and change of 
>implementation.

I am in total agreement with Marcin.  What you (Raffael) say here
sounds simply like dogma, rather than practical advice for constructing
software.

As a short practical example of what I'm saying, consider code like

   -- I am translating this from another language; apologies if I have
   -- screwed up any of the Haskell details
   nat :: Parser Int
   nat = do {c <- digit; return charToInt c} 
         `chainl1` (return \x y -> 10*x+y)

The code here parses natural numbers; it does do by parsing individual
digit characters, translating the digit characters into the
corresponding integers, and then combining the digit-integers into the
overall number.

If I understand you correctly, you would insist I write something like

   nat :: Parser Int
   nat = do {c <- digit; return charToInt c}
         `chainl1` combineDigits
            where combineDigits = return \x y -> 10*x+y

In my opinion, the code here is worse than the original.
"combineDigits" (or whatever we might choose to name it) is a one-time
function.  It is not going to be reused (it's local to "nat"; moving it
to a more-top-level scope would just cause more problems finding a good
name for it).

Introducing a name for this function does nothing more than clutter the
code.  The name provides no extra understanding.  Of course the
function is "combining digits"!  If the programmer is using chainl1, he
already knows that

   chainl1 :: Parser a -> Parser (a->a->a) -> Parser a
   -- parses a series of items separated by left-associative operators
   -- which are used to combine those items

and he can infer "combining digits" just by seeing the call to chainl1
and inspecting its left argument.


>Anonymous functions are a form of unnecessary information overload. If I 
>don't need to see how something works right here, in this particular 
>context, then don't put its implementation here. Just refer to it by 
>name.

There are more functional abstractions than there are reasonable names.

Forcing programmers to name every abstraction they'll ever encounter is
tantamount to forcing them to memorizing a huge vocabulary of names for
these abstractions.  Perhaps you can remember the precise meanings of 
ten-thousand function names off the top of your head.  I, on the other
hand, can probably recall only a hundred or so.  Thus, I must write,
e.g.

   zipWith (\x y -> (x+y,x-y)) list1 list2

rather than

   zipWith makePairOfSumAndDifference list1 list2

By only naming the most reusable abstractions (and, ideally, selecting
a set which are mostly orthogonal to one another), we provide a "core
vocabulary" which captures the essential basis of the domain.  Lambda
then takes us the rest of the way.  In my opinion, a core vocabulary of
named functions plus lambda is better than a separate name for every
abstraction.  In natural language, such a scheme would be considered
double-plus-un-good, but in programming, I think it lends itself to the
simplest and most precise specifications.


I agree with your one of your overall theses, which is that we should
focus on the "what" rather than the "how".  Where our opinions diverge,
however, is that I think sometimes the best way to communicate an
abstraction is to show the "how" inline, rather than creating a new
name in an attempt to capture the "what".

-- 
 Brian M. McNamara   lorgon at acm.org  :  I am a parsing fool!
   ** Reduce - Reuse - Recycle **    :  (Where's my medication? ;) )




More information about the Python-list mailing list