Python has closures
blade.nagaokaut.ac.jp
blade.nagaokaut.ac.jp
What he shows is some attempt to describe some kind of lexical binding. But even that looks very suspicious.
def foo():
global y
x = 0
def bar():
print x, y
bar()
x = y = 1
bar()
x = y = 2
bar()
x = y = 3
bar()
x = y = 4
bar()
x = y = 5
foo()
0 0
1 1
2 2
3 3
4 4
Above is really trivial. The problem is that the assignments change a variable and the function BAR sees the changes. So there is only one variable binding for X. In a variant where each assignments were really bindings, BAR would only see the binding in its scope and the number would not change.Above would be in Lisp:
(defvar *y* 0)
(defun foo ()
(let ((x 0))
(flet ((bar ()
(print (list x *y*))))
(bar)
(setf *y* 1 x *y*)
(bar)
(setf *y* 2 x *y*)
(bar)
(setf *y* 3 x *y*)
(bar)
(setf *y* 4 x *y*)
(bar)
(setf *y* 5 x *y*))))
Again, no closure. Just a function with a local function that gets called several times.He then describes that in a 'subfunction' a variable from an outside scope can't be set, but that is almost a side issue. It also may be that this is not often found in his code, but it is found in a lot of Lisp code that actually uses closures.
The most trivial example is a counter closure:
(let ((fn (let ((x 0))
(lambda () (setf x (+ x 1))))))
(print (funcall fn))
(print (funcall fn))
(print (funcall fn)))
1
2
3In above code FN gets bound to a closure. This closure is called three times. Each time it updates the variable X in its lexical scope.
def make_counter(name):
position = [0]
def counter():
position[0] += 1
return (name, "incr", position[0])
def show_counter():
return (name, "show", position[0])
return counter, show_counter
foo, see_foo = make_counter("foo")
bar, see_bar = make_counter("bar")
for i in range(5):
print foo()
print see_foo()
for i in range(5):
print bar()
print see_bar()
for i in range(5):
print foo()
print foo()
print see_foo()
print bar()
print see_bar()
If you run that you'll see that the returned closures retain lexical bindings to the scope they were defined in. Closures generated at different times do not interfere with each other. And closures generated in the same scope are pointing at the same variables.What more do you want?
This makes me guess that Mr. Prescod never understood what a closure is, since he failed to give any example. That one can set closed over variables in Lisp is a useful feature. He demonstrates that Python 2 can't set a variable of an enclosing scope and claims that he does not need that. Maybe if he were really using closures, he would have found it useful.
As for Pascal, you need to look again. From the beginning Pascal had the ability to pass functions and procedures as parameters to other functions and procedures. If those functions and procedures are defined in an inner scope, they will carry the original lexical scope, and are in fact full closures. OK, they are clunky to use, but they work. Skip to the end of the section starting at http://en.wikipedia.org/wiki/Comparison_of_Pascal_and_C#Func... to see the necessary syntax demonstrated.
Don't quote me on this, but I believe that Pascal was actually the very first language with full closures. All of the necessary pieces are in ALGOL-68, but I think that Pascal was implemented first and so wins.
Incidentally Sussman claims that he got the idea of lexical scope for Scheme from studying ALGOL. Of course Scheme realized the possibilities of the construct as no language before it had, and a lot of credit is due for that. But you shouldn't lightly dismiss the contributions to Lisp from languages out of the Lisp family.
The original Pascal did not have full closures. Functions did only exist as long as their surrounding function was called. They could not be returned from functions. Pascal lacked also the necessary Garbage Collection. Pascal had lexical scope, but not full closures.
All you could do was pass functions to other functions. But that's trivial, since each time one passed function X, it gets its active environment, which always is on the stack. There was no way to have closures, where functions have their own set of variable bindings, even when the surrounding function is no longer active. Being able to pass a function downwards is not sufficient to require full closures.
Basically the same applies for Algol. Functions can't be returned and are not first class objects.
What Algol contributed to the evolution of Lisp was lexical scope, but not closures. Also note that it was not Scheme that introduced closures in Lisp.
That's what I fear, many people think they know what a closure is, but in reality there is a lot of confusion.
bar is a variable whose value is a closure. In python, defining a named function just creates a variable whose value is a closure.
As for your claim that it was not Scheme that introduced closures to Lisp, I'd like to hear more about that. I've run across the claim that Scheme was from a number of sources, including http://en.wikipedia.org/wiki/Closure_%28computer_science%29, and I haven't heard of any other prior art.
def make_counter():
count = 0
def f():
nonlocal count
count = count + 1
return count
return f
c = make_counter()
for i in range(3):
print(c())
(In Python 2.x and earlier, you would probably create a Counter class to do the same thing. That approach was, and likely still is, considered more "Pythonic", by the way.)He did neither pass a function nor return one.
The function itself is not a closure. The closure is an object that bundles a function and an actual set of bindings.
I am not too familiar with python in the present and maybe the following has changed: there isn't really a definition of the language, but the documentation (which was written for the main implementation, but is the closest thing to a definition of the language) does mention that declaring a function creates a function object (closure) and assigns it to a local variable. Of course, an implementation should probably feel free to contradict the documentation when the difference is not observable.
def make_counter():
n = 0
def incr():
nonlocal n
temp, n = n, n+1
return temp
return incrAs to the advantages...
Well for one you can use the variables in closures...
Lisp has had proper support for lexical scoping and closures for ages, and nobody has ever accused it of being a leaky abstraction there, either. The Scheme example of the same program would be
(define (make-counter)
(let ((n 0))
(lambda ()
(let ((temp n))
(set! n (+ n 1))
temp))))
All that's happening here is that let is creating a new variable, and set! is looking for the nearest enclosing scope--which turns out to be the let--and assigning to that one. (Okay, there are minor semantic differences, because let creates a new scope instead of creating a new variable in the local scope, but that's not really relevant to the discussion at hand.)I don't think I understand your other question.
In Python if your function references are buried within each other deeply enough that this is even an issue you're already doing it wrong. This is not because Python is lacking power, but because you're not using the power Python actually has. With the generators, comprehensions, objects that implement __call_, bound method references, and all of the other tools available to you, you just shouldn't be defining functions in functions in functions. In Haskell where it's all functions everywhere, a function that is actually ten layer nested functions calling each other makes sense. (When using the "do" syntax sugar, every line that has <- is another nested function, so if you see ten <-s, you've got a ten-layer deep nested function. (Or eleven, if I've committed a fencepost error.))
If you're still fighting with Python by trying to jam functions in three layers deep, take a moment and try to learn to be more idiomatic. If you're in Haskell or Lisp and you never have functions three layers deep, take a moment and try to be more idiomatic. In practice, you do not need this in Python.
A great example of the Blub paradox in action ;)
Oh wait. Nobody says that about Haskell programmers? They only say it about Python? Huh. When they both have this same shortcoming with their so-called "closures"? Wonder why that is?
Anyone who's reached that point with Python is very comfortable with the idea of mutable state... everywhere else.
But a Haskell programmer who understands this and decides to accept it is just considered normal. A Python programmer who understands this and decides to accept it (as in the linked post) is declared to be a Blub user, which is essentially a polite-enough-for-HN way to say "LOL STOOPID NOOOB".
Actually not. There is no code you can write using closures modifying external state that cannot be trivially rewritten in Python using a one-element array in the outer scope which you modify in the inner (without assigning). Therefore Python has that feature in effect. It just doesn't have a piece of dedicated syntax for it.
Personally I don't mind the Python approach. It's more convenient than let/set! and I very rarely miss being able to set a variable in an outer scope.
EDIT: Come to think of it, this is just a good-enough substitute for a fraction of the stuff you can do in Lisp with Macros.
> var x = 0
Creates a new variable.
> x = 0
Assigns a variable if it has already been declared in a parent scope, or creates a new global variable otherwise.
Of course, this work break all existing Python code, so it would never happen.
Otherwise, you're making the same point that the article is making, which is that you could introduce a scoping keyword to make it easier to deal with closed-over variables.
Either way, I don't care; I'm a Ruby developer now.
I'm defining a slightly different Python syntax, in which you always have to use "var" to declare new variables, otherwise the code breaks. That includes globals. With this structure, normal closure syntax is very clean:
var x = 0
def foo():
var x = 1
def blah():
x = 2
blah()
return x
print(foo()) # prints 2The failure of the "var" idea is this code:
def getDataFile():
"returns the string 'data/data.dat'"
var name = "data.dat"
dir = "data"
return os.path.join(dir, name)
now you've clobbered the global function "dir" without realizing.The problem in javascript is that "a=12" does create a new variable, even if it's a global, and that many people just go through their code declaring only globals.
If you did get a syntax error everytime you did that, you'd soon have the habit of putting var in front of every new variable you declare.
That is the worst possible result. Requiring an explicit local or global keyword is reasonable, defaulting to local is reasonable, defaulting to global is insane.
x = 5
I think there should be a "var x" either locally or globally -- SOMEWHERE -- and actually there should be a compile error if "var x" is missing.
You're the first person I read who actually defends this feature of JavaScript. (Crockford lists it in his "terrible parts" I believe.)
I like it because it involves one less keyword in the grammar vs the Python 3 solution. Though tptacek makes a good point (I haven't myself had trouble with that, but I can easily see why others might.)
This is the blubbiest non-ironic statement I can remember reading.
OTOH, one nice aspect in say ruby is the combo "real" anonymous functions + the syntax f a equivalent of f(a), which is what makes DSL possible in ruby (and impractical in python in general). I think it comes at a price in readability, though.
Thanks for clearing this up.
Actually, if you could pass this on to people when you hear them refer to lambdas as closures, that would be pretty awesome.
JavaScript, on the other hand, allows you to define the inner function anywhere in the local scope and makes closures much more attractive, IMO.
Changing this may mean big changes to the interpreter and so may not be worth it. I wonder if lambda created closures are any different...probably not.
In order to make it work Python would have to introduce a scope-blocking structure like braces, parens, or an 'endlambda', all of which I think are steps in the wrong direction, especially given Python's great feature of semantic whitespace. I'll take a clean function defined above over braces.
I do know of a way to hack a multi-line Lambda with existing syntax, though, but I have no guarantees about it. I don't think I've used it in serious code, since it's just real ugly.
k = lambda x: eval(compile("""
print x
y = 4
print x + y
x = 8
print x
""", '', 'exec'))
x = 5
k(2)
# 2
# 6
# 8
print x
# 5 (let ((x 1))
(defun less () (incf x))
(defun more () (decf x)))