Named code blockes

Alex Martelli aleaxit at yahoo.com
Tue Apr 24 08:45:12 EDT 2001


<James_Althoff at i2.com> writes:

> Alex Martelli writes:
>
> > Unnamed blocks are a very powerful programming device.  As far as I can
>
> But where's the extra power in making them UNNAMED?  It's
> so easy to name them, after all.
    [snip]
> <jim response>
>
> Granted, it is "easy" to name a code block, but I don't think it
> is very graceful (personal preference, obviously).
    ...
> obviously look very different.  This is just my experience, but I find --
> in
> the Python code that I see -- very few examples of "collection.do()" -type
> methods, whereas in Smalltalk, this is a very common design pattern
> (see "Smalltalk Best Practice Patterns", Kent Beck, page 146, for
example).

But why should the same design patterns (I'd call them idioms, but
that's just a nuance) be *BEST* in every language?!  In Haskell it's
a common and elegant design pattern to use pattern matching to check
a list's structure, process its head thus obtained, and recurse on its
tail.  You'll find very few examples of this idiom in the Python code
that you see...!  *SO WHAT*?  Python *enables* obtaining the head and
tail of a list and doing a recursive call -- that doesn't make that
the _idiomatic_ Python way to loop, of course.  Python *enables*
building a "code block" (with a name -- a local nested function or
other callable) and passing it do some object's method -- but THAT
is not idiomatic Python for looping, either.

Should EVERY language on Earth contain all the constructs that
somebody coming from OTHER languages would find most idiomatic
and handy in the ORIGINAL language?  Specifically, should Python
do so, throwing simplicity to the dogs in the pursuit of utterly
tiny "syntax-elegance advantages" in stuff it CAN perfectly well
do right now (getting the head and tail of a list, defining a
code block to pass as an argument, ...) but not with QUITE the
same syntax sugar as other languages which privilege such kinds
of operations by idiom (ML or Haskell pattern-matching, Ruby or
Smalltalk codeblocks, ...)...?

This seems to me to be very much in the same spirit as other
recent or current threads demanding (what the various respective
posters consider) "perfect" syntax sugar for do-until loops,
assignments within an if's condition, declarations of variables,
and so on, and so forth.

It's just about NEVER enough, apparently, to show -- "you CAN
perfectly well do this RIGHT NOW, with MINISCULE syntax sugar
changes from your heart's desire" -- oh no, it HAS to be JUST
EXACTLY _THAT_ syntax sugar, or the demands will never cease.

"while 1:"/"if <cond> break" is not acceptable syntax sugar
for "do"/"until <cond>", for example -- oh no, let's build
an entirely new, different, incompatible language just so we
can spell this differently (at least THAT one didn't want to
add his favourite sugar to Python itself:-).

One genius clamored for a huge new mechanism that would at
last, in the Plenitude of Glory, let him write "let x = y"
versus "set x = y" so he'd get ``declarations'' -- and then,
when somebody showed him how easily he could set things up
so as to write "let.x = y" and "set.x = y", he claimed his
coworkers would kill him if he programmed that way.  Well
isn't that obvious, that being able to have a SPACE there
instead of a PERIOD is the be-all, end-all of programming?!
Isn't it _absolutely_ obvious that placing a period there
will lead to justified homicide...?


> I'm just postulating that the extra -- very small though it might
> seem -- burden of defining named functions
> along with the diffence in syntax between method calls versus built-in
> control structures along with the "confusing-or-non-obvious-for-beginners"
> notion of nested functions defined within other functions is sufficient
> enough to discourage many programmers from using this design pattern very
> much in Python code.

"And this is bad _because_...???"

Do the SAME idioms have to be natural, most-elegant, and optimal
in EVERY programming language?

Python's idiom for looping on a collection is based on iterators.
See PEP 234, open and under active discussion for Python 2.2, for
a likely way to formalize a notion that, while perfectly workable
since a long time ago, rested on as solid underpinnings.

Why would, or should, Guido van Rossum go out of his way and
add further features to the language to support another different
idiom for looping on a collection _with postulatedly greater
elegance_ (it's already well supported today BUT needs a tiny
extra burden -- including understanding the Python language
well enough to see how easy it makes to nest functions:-)...?

The 'control block passed to some other function' and 'iterator'
idioms/patterns generalize optimally along different axes.

Iterator objects make "the state of the loop" into a useful
concrete object, letting the framework, or client-code, do
some loop-advancing steps suitably intermixed with all sorts
of different processing (several loops can be going on at the
same time, nestedly or in parallel, etc, etc).  Function
arguments (or codeblock arguments) allow other kinds of
functional manipulation quite apart from looping -- the
callable can be stored by the object receiving it and come
into play later in all sorts of situations, for example.

I'm happy indeed to have both kinds of building-blocks in
a language!  But I'm also quite happy that no complication
has been added to the language to favour 'unnamedness'
(well, actually, I'd be even happier if no unnamedness for
code blocks was there -- it IS there, via lambda, but I
do not particularly appreciate the "extra" [?] abilities
this minor-annoyance feature buys me:-).


> It's just a theory.

I can accept as a working hypothesis that the "tiny extra
burden" helps convince people to use for loops and list
comprehensions, the natural Python idioms, more than they
use the passing of code blocks to other methods.  It's in
a sense a pity that both kinds of idioms are there, often
neither "the obviously right way" --
    bleep = map(lambda x: x+3, filter(lambda x: x>4, myseq))
or
    bleep = [x+3 for x in myseq if x>4]
or
    bleep = []
    for x in myseq:
        if x>4:
            bleep.append(x+3)
or
    def add3(x): return x+3
    def ifgt4(x): return x>4
    bleep = map(add3, filter(ifgt4, myseq))
or...?  Oh well -- so it goes.  I _would_ rather have
"one obviously right way", but history, need for backwards
compatibility, etc, obviously hamper that ideal dream.

There's still quite a gap from that to advocating going
out of one's way to add yet MORE perplexing alternatives
to a language which, despite existing multiplicity, still
enjoys more simplicity than most others out there:-).


Alex






More information about the Python-list mailing list