Why is Python popular, while Lisp and Scheme aren't?

Martin Maney maney at pobox.com
Wed Nov 13 00:42:31 EST 2002


Brian Quinlan <brian at sweetapp.com> wrote:
> People make frequent mistakes with inline assignment in other languages
> (e.g. C), so it shouldn't be allowed.

You'll be wanting to throw out all manner of things on that basis, since
there's nothing of much use that hasn't been the source of problems for
some.  I know, you have to draw the line somewhere, but to me this seems
like a good deal of value to lose for what IME is little gain in
idiot-proofing.  I can agree that the value seems to be lower in Python in
that the need for this arises less often than in, say, C.  I haven't yet
decided if I think that's due more to the language itself or to the way the
lack of operator= has led to the construction of facilities to make it
unnecessary for common uses.  :-/

Mind, if the real answer is "Because Guido doesn't like it", I can reconcile
myself to that.  I'm just wondering if there's some other, more articulable,
reasoning at work.  (I guess I am saying that I don't consider "people make
mistakes" a reason, at least not much of one.  Possibly I have, for whatever
reason, had a great deal less trouble with this than average.  (hmmm,
average *what*, exactly?))

> I don't think that indentation has anything to do with this.

Think about the straightforward implementation of this in legal Python with
less undersized indentation than I used before:

	for l in lines:
		m = re1.match(l)
		if m:
			... process type 1
		else:
			m = re2.match(l)
			if m:
				... process type 2
			else:
				m = re3.match(l)
				if m:
					... process type 3

It interacts in that the non-operator assignment makes it imposible to use
elif, so that each case has to buy another indentation level.  And, yes,
that could be avoided by repeating the match for the case that succeeded,
but that seems about equally ugly to me:

	if re1.match(l):
		m = re1.match(l)
		...
	elif re2.match(l):
		m = re2.match(l)
		...

> I'd write that as:
> 
> def process_type_1(first, second, ...):
>    process type 1 record ...
> 
> def process_type_2(first, second, ...):
>    process type 2 record ...
> 
> processing_rules = [(r'....', process_type_1),
>                          (r'....', process_type_2),
>                    ...]
> 
> 
> compiled_rules = [(exp.compile(), func) for (exp, func) in
> processing_rules]
> 
> for l in file.readlines():
>    for exp, func in compiled_rules:
>        match = exp.match(l)
>        if match is not None:
>             apply(func, m.groups())
>             break

Yes, that approach occurred to me.  It seemed, and still seems, like a great
deal of overhead and effort for little if any gain in clarity, although it
certainly does solve the marching right off the screen problem.

> Notice that:
> - it is very easy to add new record types

You have two things that have to be added for each new case: a regexp and a
code block.  This doesn't allow much if any better propinquity of
corresponding regexes and code; neither does the savings in explicit logic
boilerplate appear to outweigh the function-form bolierplate it requires. 
Now, if Python had something like lambda that could be used to define a real
function, not just an expression's worth of code, I might like this better,
since then the regex and code could actually be brought together.  But it
doesn't.

More generally, making it easier to add cases is not itself an advantage
here.  And adding generality is not always a win, since there's usually some
cost... as I know too well, because I am prone to err in that direction
myself.  :-)

> - record processing is more modular

In general, yes.  Not significant: the processing is usually very simple,
along the lines of reordering the fields, dropping a few, maybe pasting two
together.

> - the code is pretty simple

But not IMO as simple as the straightforward way of writing it, at least not
at the scale involved here.


The average number of patterns and rules for each file's data is probably
under two; there are a great many whose processing is really trivial, and
the combined recognition of a valid datat line and parsing by the regex is
the real meat of it.  I've long since refactored this to make those cases
quite small - a list of parameters and the stylized parsing function that is
on the order of one screen of code.  But there are quite a lot of files, and
some of them are a good deal messier, and it is these latter that I have
mostly described - because they were where the problem became noticeable.  I
think the worst have about six pattern/action pairs (although there may be
worse ones yet to come to my attention).  Anyway, each file is handled
separately, so adding a new file type doesn't touch any existing code at
all for any of these approaches.


BTW, I'd appreciate not being emailed a reply unless you're not posting
publicly; that's just the way I am.  Thanks.

(hmmm, gotta migrate the random quote hack over to this machine...)



More information about the Python-list mailing list