> Most Lisp compilers tell you about
> undeclared variables.
Perhaps you are correct -- I haven't programmed professionally in Lisp for 16 years. But back then Lisp certainly did not typically warn against assignment to a variable that had not first been declared.
> Surely not. It is one of the essences of
> Functional Programming.
But Python isn't a functional programming language. Sure, it borrows many nice features from Lisp, but it encourages a somewhat different programming style. In Python, full lexical scoping would only be a nicety. Adding it would not greatly enhance the Python programming experience. For instance, Python lists work differently than Lisp or Haskell lists. They are very good at what they do, but they are not really ideal for functional or recursive programming styles.
> Funny, Python's efficiency (without native code
> compilers;-) )? If you look through the
> GC literature you see that reference counting
> is considered not to be the memory management
> algorithm of choice (besides some special uses).
And to some extent, Python has proved the literature wrong. Python's reference-counting GC is one of the reasons that Python is extremely portable and consequently very popular. It is very difficult to make an efficient and portable non-reference-counting garbage collector. Python took the choice of practicality, rather than being theoretically optimal. I mysself was pretty dubious when I heard that Python used a ref-counting GC, but it won me over.
For instance, with a ref-counting GC, the life-time of objects is well-defined, and consequently, object destructors become very useful things. Constrast this with Java where destructors are basically useless. Furthermore, it turns out that cycles are not much of a problem to deal with. They don't occur all that often, and when they do, they can usually be easily and automatically broken in destructors.
I think that Python has shown (since well-defined destructor behavior is so useful) that GC'ed languages should have ref-counted garbage collectors as their main garbage collectors, and then have a full garbage collector as a backup to get rid of objects with cycles. This is, in fact, what Python 2.0 does. It provides a true backup GC that can be optionally turned on, if you need it.
|>oug
P.S. I'm not sure that you are correct about no Lisp using reference-counting. The last time I looked at GC literature, there were some that used a "one, two, many" reference-count for dealing with short-lived objects. Perhaps my knowledge on this, however, is also out of date.
"Gratuitous guesswork"? There is no gratuitous guesswork in Python's scoping rules. They are perfectly well-defined, simple, and easy to understand.
I agree that it would be better if all variables had to be declared before being assigned to. Not enforcing this causes bugs due to typos that would otherwise be immediately discovered by the interpreter. But Python is far from the only language with this flaw. Most
dialects of Lisp (not including Scheme) and Perl also suffer from this problem (although with Perl I suppose there is a way of running in a paranoid mode that will give you warnings about this type of problem).
Regarding functions picking up their enclosing lexical variables, this would certainly also be nice, but is really not much more than a nicety. Almost anytime you would need a closure, you can do the same thing just as easily using object instance variables or default arguments to functions. Sometimes this requires a bit more typing, but that's the only downside. (And, in fact, by using default arguments, you get an explicity list of the variables that a function is importing from an enclosing scope, and this can often increase the clarity of the code.) On this issue, Python made the trade-off of being more efficient and portable. Implementing closures requires having a real garbage collector, and in the ability to copy stack frames to the heap, which has significant portability and efficiency ramifications. Despite this, full lexical scoping and true garbage collection are on the slate for future versions of Python. How this can be done without damaging Python's efficiency and portability remains to be seen.
I'm not saying that I have no complaints with Python -- I, in fact, have many. But I have used a lot of languages and I have many complaints with all of them. I have far fewer complaints with Python that with any other language I have yet used.
By your argument C would have never have largely displaced Fortran and Cobol, and C++ would never have largely displaced C, and Java would have never largely displaced C++. Python is becoming more and more popular because many people are greatly disatisfied, perhaps even nauseated by Perl, yet they need a language that addresses more or less the same problem domain. You don't see many fans of Fortran ranting against C, do you? Fortran fans more mostly just happy doing things the same bad old way that they did things 40 years ago and are blissfully ignorant of the advantages that a more modern language would bring them. On the other hand, Python fans need to rag on Perl, because if they can't convice people that there is good reason to use Python rather than Perl, then people will take the path most travelled -- which is to use Perl.
Python is not dynamically scoped! In a dynamically scoped language, a variable left unbound in the local scope (and intended to name a global variable) can be inadvertently shadowed by a variable of the same name in a calling procedure. This can't happen with Python because in Python all variables unbound in the local scope refer to global variables. Furthermore, for most purposes, lexical scoping can be simulated in Python using default arguments.
> Most Lisp compilers tell you about
;-) )? If you look through the
> undeclared variables.
Perhaps you are correct -- I haven't programmed professionally in Lisp for 16 years. But back then Lisp certainly did not typically warn against assignment to a variable that had not first been declared.
> Surely not. It is one of the essences of
> Functional Programming.
But Python isn't a functional programming language. Sure, it borrows many nice features from Lisp, but it encourages a somewhat different programming style. In Python, full lexical scoping would only be a nicety. Adding it would not greatly enhance the Python programming experience. For instance, Python lists work differently than Lisp or Haskell lists. They are very good at what they do, but they are not really ideal for functional or recursive programming styles.
> Funny, Python's efficiency (without native code
> compilers
> GC literature you see that reference counting
> is considered not to be the memory management
> algorithm of choice (besides some special uses).
And to some extent, Python has proved the literature wrong. Python's reference-counting GC is one of the reasons that Python is extremely portable and consequently very popular. It is very difficult to make an efficient and portable non-reference-counting garbage collector. Python took the choice of practicality, rather than being theoretically optimal. I mysself was pretty dubious when I heard that Python used a ref-counting GC, but it won me over.
For instance, with a ref-counting GC, the life-time of objects is well-defined, and consequently, object destructors become very useful things. Constrast this with Java where destructors are basically useless. Furthermore, it turns out that cycles are not much of a problem to deal with. They don't occur all that often, and when they do, they can usually be easily and automatically broken in destructors.
I think that Python has shown (since well-defined destructor behavior is so useful) that GC'ed languages should have ref-counted garbage collectors as their main garbage collectors, and then have a full garbage collector as a backup to get rid of objects with cycles. This is, in fact, what Python 2.0 does. It provides a true backup GC that can be optionally turned on, if you need it.
|>oug
P.S. I'm not sure that you are correct about no Lisp using reference-counting. The last time I looked at GC literature, there were some that used a "one, two, many" reference-count for dealing with short-lived objects. Perhaps my knowledge on this, however, is also out of date.
"Gratuitous guesswork"? There is no gratuitous guesswork in Python's scoping rules. They are perfectly well-defined, simple, and easy to understand.
I agree that it would be better if all variables had to be declared before being assigned to. Not enforcing this causes bugs due to typos that would otherwise be immediately discovered by the interpreter. But Python is far from the only language with this flaw. Most dialects of Lisp (not including Scheme) and Perl also suffer from this problem (although with Perl I suppose there is a way of running in a paranoid mode that will give you warnings about this type of problem).
Regarding functions picking up their enclosing lexical variables, this would certainly also be nice, but is really not much more than a nicety. Almost anytime you would need a closure, you can do the same thing just as easily using object instance variables or default arguments to functions. Sometimes this requires a bit more typing, but that's the only downside. (And, in fact, by using default arguments, you get an explicity list of the variables that a function is importing from an enclosing scope, and this can often increase the clarity of the code.) On this issue, Python made the trade-off of being more efficient and portable. Implementing closures requires having a real garbage collector, and in the ability to copy stack frames to the heap, which has significant portability and efficiency ramifications. Despite this, full lexical scoping and true garbage collection are on the slate for future versions of Python. How this can be done without damaging Python's efficiency and portability remains to be seen.
I'm not saying that I have no complaints with Python -- I, in fact, have many. But I have used a lot of languages and I have many complaints with all of them. I have far fewer complaints with Python that with any other language I have yet used.
By your argument C would have never have largely displaced Fortran and Cobol, and C++ would never have largely displaced C, and Java would have never largely displaced C++. Python is becoming more and more popular because many people are greatly disatisfied, perhaps even nauseated by Perl, yet they need a language that addresses more or less the same problem domain. You don't see many fans of Fortran ranting against C, do you? Fortran fans more mostly just happy doing things the same bad old way that they did things 40 years ago and are blissfully ignorant of the advantages that a more modern language would bring them. On the other hand, Python fans need to rag on Perl, because if they can't convice people that there is good reason to use Python rather than Perl, then people will take the path most travelled -- which is to use Perl.
Python is not dynamically scoped! In a dynamically scoped language, a variable left unbound in the local scope (and intended to name a global variable) can be inadvertently shadowed by a variable of the same name in a calling procedure. This can't happen with Python because in Python all variables unbound in the local scope refer to global variables. Furthermore, for most purposes, lexical scoping can be simulated in Python using default arguments.