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

Martti Halminen martti.halminen at kolumbus.fi
Sat Nov 23 22:00:47 EST 2002


Alexander Schmolck wrote:

> Of coure LOOP and FORMAT affect newcomers! They are extremely commonly used
> constructs, so you will encounter them quite frequently in other people's
> code. And even simple uses of LOOP can easily yield misunderstanding unless
> you have some fairly good understanding of what it does (the emulation of
> plain English is additionally deceptive in this regard):
> 
>      (loop for x below 5 for y = nil then x collect (list x y))
>           => ((0 nil) (1 1) (2 2) (3 3) (4 4))
> 
> as opposed to:
> 
>      (loop for x below 5 and y = nil then x collect (list x y))
>           => ((0 nil) (1 0) (2 1) (3 2) (4 3))

If it is any consolation, neither LOOP nor FORMAT were noncontroversial
in the Lisp community when they appeared, mostly due to their
"non-lispy" look and feel. There are some notable Lispers, like Paul
Graham, who don't usually use LOOP.
FORMAT is nearly-universally used, though somebody claimed that it is a
separate, Turing-complete programming language in its own right:-)
- LOOP isn't the only iteration construct: I use usually DOTIMES, DOLIST
or the mapping functions for simple cases. The old DO also exists for
oldtimers.

> Hmm, I thought untyped means that variables don't have any type associated
> with them at all (like in assembler).

In CL, the variables may contain any type of objects, but any piece of
data has a known type (unlike in C, where you can cast stuff however you
like, whether it makes any sense or not).

> > Well, the battle was decided (temporarily?) in favor of static languages
> > during the long decades before systems routinely shipped with ghz processors
> > and hundreds mb ram. By the time those systems came along, almost everyone was
> > using static languages. Folks don't change easily, so CL still does not get
> > used widely.
> 
> This explanation has the considerable problem that it would equally have
> predicted the miserable failure of Perl, Python, Javascript and I'd guess
> Visual Basic.

Except that those are rather new languages in comparision, from a time
the machine performance had already risen to acceptable values. For
comparision, at the time Lisp Machines were the fastest workstations on
the planet, they had clock frequencies like 4 MHz. The competition ran
16 MHz Motorola 68020:s.
(Cray 1 had 80 MHz, IIRC.)

 > Well, it's not just "pragmatic advantages", I do believe that in some
points
> python's *design* is just superior. Iteration and container classes seem
> fairly crufty to me in CL (not knowing CL that well, I might be wrong, in
> which case I'd much appreciate to be enlightend).

No such thing as "iteration class" in the language: Lisp had already
existed for a quarter century before it got a standardized object system
(plenty of non-standard, non-compatible versions before that), so the
control flow constructs are rather othogonal to the object system.

Also, no container class in the meaning of unifying lists and hash
tables. On the other hand, the language has what CL calls sequences,
i.e. plenty of stuff work the same on lists and one-dimensional arrays
(including strings).

 
> Now if you want to define you own collection classes, you're really in for a
> hard time:

I fail to see what is so hard in that. Obviously you have to design your
own wrapper class if you want similar behaviour from different data
structures, given that the language doesn't have it built-in, but as you
yourself show, any given operation is only a few lines.
> python:                           CL:
> 
> 
>  x = list[index]                   (elt arrayOrList index)
>  x = hash[key]                     (gethash key  hash) 
                                     ;; *why* this arg-order?
               Why not? It is consistent with most of the language, most
similar functions are defined as (<operation> <item> <containing
object>). The major exceptions are where there may be variable amount of
arguments, like
array indices: (aref <array> <ind1> <ind2> ....<indN>). ELT probably for
similarity with AREF.

>  x = myType[indexOrKey]            ; no generalized item access
					(elt sequence index) works for all 						sequence types. For your
own types you can define whatever accessor patterns you like. There are
tools to make your accessor to work with the generic assignment command
(setf <place> <value>)

> 
> 
> 
>  del container[indexOrKey]         ; no generalized deletion mechanism
                                  (delete item sequence) for all
sequence types, (remhash key table) for hash tables. Not that difficult,
I'd think.
> 
>  container[indexOrKey] = x         (setf (elt arrayOrList index) x)
>                                    (setf (gethash key hash) x)
> 
> 
> for item in list:                  (loop for item in list)
>     print item
                                     (loop for item in list
                                         do (print item)) ; to be exact

> for key in dict:                   (loop for key being the hash-keys of h
>     print key                       do (princ key))
> 
> for value in dict.values():        (loop for value being the hash-values of h
>     print value                     do (princ value))

                            Alternative ways for playing with hash
tables: MAPHASH and WITH-HASH-TABLE-ITERATOR.


> 
> for item in container:             ; no convienient idiom (?)
>     print item

              - For printing the usual idiom is usually just (print
container), though hash tables do not have a defined machine-readable
output form. Nothing to prevent you from defining one.

> LOOP does offer monstrous complexity, but no mechanism to extend it to handle
> anything beyond integers, lists, arrays and hashs.

Already handles also floats, rational numbers, complex numbers (with
some care in end test due to the mathematical properties of complex
numbers: FROM ... TO isn't well defined), strings and packages (symbol
tables).
For that matter, it is a macro, and sources are available, so expanding
it to handle anything else you wish is possible, with no runtime
performance implications. Not that many wish: it is quite sufficiently
complex already for most people.

> Similarly, functions like
> concatenate only know about lists and arrays (which all can't even be
> subclassed, right?).
- Strings too, as a subclass of arrays. As that was about all
system-defined types with sensible semantics for concatenation, I don't
know what you are missing. I've never had any reason to wish subclass
built-in types, so I don't see it as a problem.
 
> This really looks like quite a big disadvantage in abstraction and
> convienience when compared to python.

To some extent this is a style difference in language usage: you seem to
want something like C++ -style overloading, making your own
constructions to hide in built-in behaviours. Most CL programmers are
happy to leave the language built-in parts alone (unless explicitly
defining a new language for some reason), and defining their own stuff
with different names, thereby reducing surprises for readers. In reading
somebody's C++ code I can never guess what + does this week, reading CL
I can be relatively safe assuming (+ a b) sums numbers, (plus a b) is
probably my own matrix multiplication stuff in my code [unless it
happened to be old Maclisp stuff...].

Now what tools did Python have to define your own control flow
constructs ? :-)
 
--



More information about the Python-list mailing list