Python syntax in Lisp and Scheme

Alex Martelli aleax at aleax.it
Wed Oct 8 10:22:43 EDT 2003


Doug Tolton wrote:
   ...
> Alex, this is pure un-mitigated non-sense.

Why, thanks!  Nice to see that I'm getting on the nerves of _some_
people, too, not just having them get on mine.

> Python's Metaclasses are
> far more dangerous than Macro's.  Metaclasses allow you to globally
> change the underlying semantics of a program.

Nope: a metaclass only affects (part of the semantics of) the
classes that instantiate it.  No "globally" about it.  When I
write a class I can explicity control what metaclass it uses,
or inherit it.  E.g., by writing 'class My(object):', with no
explicit metaclass, I ensure type(my)==type(object).  The type
of the built-in named 'object' is the built-in named 'type'
(which most custom metaclasses subclass), which is also the
type of most other built-in types (numbers, strings, list,
tuple, dict, functions, methods, module, file, ...).  I.e.,
your assertion is pure un-mitigated FUD.

> Macros only allow you
> to locally change the Syntax.

"Locally"?  Not globally?  Care to explain?  Each 'invocation'
(expansion) of a macro must occur in a particular locus, sure,
but isn't the _point_ of (e.g.) defining a 'loop-my-way' macro
that every occurrence of 'loop-my-way' is such an expansion?

As for that mention of "the Syntax" AS IF somehow contrasted
with the "underlying semantics" just before, don't even bother
to try explaining: one example of macros' wonders offered by a 
particularly vocal and emotional advocate was a macro
'with-condition-maintained' that was somehow supposed to make
whatever alterations might be needed in the control program of
a reactor in order to regulate temperature -- and it was
passed that code as three calls to functions (or expansions
of macros) NOT defined inside it, so how it could possibly
work "only...locally", when to do anything at all it MUST
necessarily find, "expand", and alter the local instantiations
of those functions (or macros)...?!

If that's an example of "only allow you to locally change
the syntax", what would be an example of *EVEN DEEPER
AND MORE PERVASIVE* changes ?!

> Your comparison is spurious at best.

What "my comparison" are you blabbering about?  My text that
you quoted, and called "pure un-mitigated non-sense", had no
"comparisons", neither my own nor others'.  I see YOU attempting
to draw some "comparison" (eminently spurious, to be sure) 
between metaclasses and macros...


> Your argument simply shows a serious mis-understanding of Macros.
> Macros as has been stated to you *many* times are similar to
> functions.  They allow a certain type of abstraction to remove
> extraneous code.

Yeah, right.  Kindly explain that 'with-condition-maintained'
example and the exhalted claims made and implied for it, then.


> Based on your example you should be fully campaigning against
> Metaclasses, FP constructs in python and Functions as first class
> objects.  All of these things add complexity to a given program,

"FUD" and "nonsense" (with or without a hyphen) would be serious
understatements in an attempt to characterize *THIS*.  *HOW* do
"functions as first class objects" perform this devilish task of
"adding complexity to a given program", for example?!  The extra
complexity would be in rules trying to FORBID normal usage of an
object (passing as argument, returning as value, appending to a
list, ...) based on the object's type.  There is obviously no
complexity in saying "_WHATEVER_ x happens to stand for, you
can correctly call somelist.append(x)" [passing x as argument to
a method of the somelist which appends x to the list], for example.
The added complexity would come if you had to qualify this with
"UNLESS ..." for whatever value of ``...''.

> however they also reduce the total number of lines.  Reducing program
> length is to date the only effective method I have seen of reducing
> complexity.

For some (handwaving-defined) "appropriate" approach to measuring
"length" (and number of lines is most definitely not it), it is ONE
important way.  But you're missing another crucial one, which is
the count of interactions, actual and potential, between "parts"
of the program -- the key reason why global effects do not in fact
effectively reduce complexity, but rather bid fair to increase it,
even though they might often "reduce the total [[length]]", is
exactly this.  E.g., if large parts of my program needed all kinds
of comparisons between strings (including comparison-related
functionality such as hashing) to be case-insensitive, it might
make my program 'shorter' if I could set case insensitivity as
the global default -- but it might easily mess up totally unrelated
and otherwise stable modules that rely on the usual case sensitive
operations, causing weird, hard-to-trace malfunctionings.  I've
mentioned my youthful APL experiences: with its quad-IO to globally
set index origin for arrays, and its quad-I forget what to globally
set comparison tolerance in all comparisons between floating point
numbers, APL was a prime example of this (among other things,
reusability-destroying) global-effects risk.  Sure, it was cool
and made my program shorter to be able to check if "a < b" and
have this IMPLICITLY mean "to within N significant digits" (or
whatever) -- but it regularly broke other otherwise-stable modules
and thus destroyed reuse.  Not to mention the mind-boggling effects
when a<b, a>b and a=b can ALL be 'true' at once thanks to the
"to within N significant digits" IMPLICIT proviso...

Complexity is not just program length, and reducing program length
not the only important thing in reducing complexity.  Removing
*repetition* (boilerplate), sure, that's nice -- and if there was
a way to constrain macros to ONLY do that (as opposed to ending up
with examples such as 'with-condition-maintained', see above) I
would be very interested in seeing it.  I doubt there is one, though.


> If you truly believe what you are saying, you really should be
> programming in Java.  Everything is explicit, and most if not all of

Hmmm, one wonders -- are you a liar, or so totally ignorant of what
you're talking about that you don't even KNOW that one of Java's
most "cherished" features is that the "self." is just about ALWAYS
implicit...?  Anyway, in my text which you quoted and characterized
as "pure un-mitigated non-sense" I was speaking of UNIFORMITY as
a plus -- and Java's use of { } for example ensures NON-uniformity
on a lexical plane, since everybody has different ideas about where
braces should go:-).

But I've NEVER argued in favour of boilerplate, of repetitiousness.
I think that the occasional error that you can catch by forcing
redundancy is generally outweighed by all the errors that just
would not be there if the language let me state things "once, and
only once".  So, for example, when I write
    x = 23
I most definitely don't WANT to have to redundantly state that,
by the way, there is a variable x, and, whaddyaknow, x refers
to an integer.  As to whether it makes more sense to later let
the same name x in the same scope refer to OTHER objects (of
the same type; or, of any type) -- I still don't know; maybe
a single-assignment kind of functional language would in fact be
preferable, or maybe Python's relaxed attitude about re-bindings
is best, or maybe something in-between, allowing re-bindings but
only within a single type's items (for "re-bindings" you may
choose to read "assignments" if you wish, I'm not trying to
reopen THAT particular lexical flamewar for further debate;-).

So far, I'm pretty happy with Python's permissive approach to
mutation and re-binding, but I notice I don't mind (differently
from many others) the inability to re-bind SOME references
(e.g., items of tuples, or lexically-outer names) -- and in
Haskell or ML I don't recall ever feeling confined by the
inability to have the same name refer to different values at
successive times (in the same scope).  [I _do_ recall some
unease at being unable to mutate "large" data structures, as
opposed to rebinding simple names, so it's not as if I can
claim any natural affinity for the functional [immutable-data]
approach to programming -- I just wonder if perhaps the current
widespread _emphasis_ on rebinding and mutation may not be a
TAD overdone -- but, enough for this aside].

I do, of course, truly believe in what I'm saying -- what
WOULD have stopped me from taking up any of a zillion different
languages, instead of Python, when I started studying it
about four years ago?  Indeed, my opportunities for making
money, and the audience for my books, would be vaster if I
had stuck with what I was mainly using at work then (mostly C++,
some Java, VB, Perl), my academic respectability higher if I
had stuck with Haskell or some ML.  But while I don't mind
money, nor fans, I care most about other values -- and the
amount to which "Python fits my brain" and makes me most
comfortable and productive meets and exceeds all claims I had
heard to this effect, PLUS, I have experiential proof (enough
to convince me personally, if nobody else:-) that it's just
as comfortable and productive for many others, from programming
newbies to highly experienced professionals.  Sure, Java would
let me program my cellphone (which currently doesn't support
Python) -- oh well, I'll have to eschew that crucial pursuit
for a while longer now...


Alex





More information about the Python-list mailing list