[Python-ideas] A "local" pseudo-function
Steven D'Aprano
steve at pearwood.info
Tue May 1 14:00:23 EDT 2018
On Tue, May 01, 2018 at 09:26:09PM +1200, Greg Ewing wrote:
> Steven D'Aprano wrote:
> >So what was the closure? If the surrounding function was still running,
> >there was no need to capture the running environment in a closure?
>
> You seem to be interpreting the word "closure" a bit
> differently from most people. It doesn't imply anything
> about whether a surrounding function is still running or
> not.
>
> A closure is just a piece of code together with a runtime
> environment.
That's not *all* it is, because obviously *every* function has both a
piece of code and a runtime environment.
y = 1
def func():
x = 2
return x+y
Here, there's a local environment as well as an implicit global one.
Surely we don't want to call this a closure? If we do, then all
functions are closures and the term is just a synonym for function.
Wikipedia gives a definition:
a closure (also lexical closure or function closure) is a
technique for implementing lexically scoped name binding
in a language with first-class functions. Operationally,
a closure is a record storing a function together with an
environment.
https://en.wikipedia.org/wiki/Closure_%28computer_programming%29
but also warns
As different languages do not always have a common definition
of the lexical environment, their definitions of closure may
vary also
and explicitly says that Pascal (at least standard Pascal) didn't do
closures:
Traditional imperative languages such as Algol, C and Pascal
either do not support nested functions (C) or do not support
calling nested functions after the enclosing function has
exited (GNU C, Pascal), thus avoiding the need to use closures.
Neal Gafter gives what I believe is *the* standard definition of
closures, at least in academic and functional programming circles,
probably taken from Guy Steele and Scheme:
A closure is a function that captures the bindings of free
variables in its lexical context.
http://gafter.blogspot.com.au/2007/01/definition-of-closures.html
Since Steele basically wrote the book on closures, I think we ought to
take his definition seriously :-)
(That's also the definition I was thinking of.)
By this definition, if there are no free variables, or no captured
bindings, then its not a closure. func() above isn't a closure, since
"x" isn't a free variable, and while "y" is, the value of it isn't
captured.
Unfortunately, the terminology has become a real mess, especially since
the technique has moved into languages like Ruby and Javascript. Martin
Fowler declares that closures, lambdas and blocks are the same thing:
https://martinfowler.com/bliki/Lambda.html
although he does admit that technically you can have lambdas that aren't
closures. I think Fowler is abusing the terminology since all three of
his terms are orthogonal:
- closures can be created with def or lambda and are not
necessarily anonymous;
- lambda comes from the lambda calculus, where it refers to
anonymous function expressions, not specifically whether
they capture the value of free variables in their environment;
- "block" typically refers to the structure of the source code;
in Ruby it also refers to a kind of first-class anonymous
callable object. Such blocks may, or may not, contain free
variables.
At least I don't use this definition of closure:
"a closure is a callback that Just Works."
https://reprog.wordpress.com/2010/02/27/closures-finally-explained/
*wink*
> In typical Pascal implementations, a closure
> is represented by a (code_address, frame_pointer) pair,
> where the frame_pointer points to a chain of lexically
> enclosing stack frames. The language rules make it possible
> to manage the frames strictly stack-wise, which simplifies
> the memory management, but that doesn't make the closure
> any less of a closure.
Well... it's a pretty feeble closure, since Pascal doesn't support
functions as first-class values. More like second-class.
The c2 wiki describes Pascal:
However, when a function is passed to another function
and later called, it will execute in the lexical context
it was defined in, so it is, IN SOME SENSE [emphasis
added], "closed over" that context.
http://wiki.c2.com/?LexicalClosure
but I think that sense is the same sense that func() above is "closed
over" the free value y. The loosest possible sense.
If we accept that "Pascal has closures", they're pretty crap closures,
since they don't let you do any of the interesting and useful things you
can do in languages with "real" closures like Scheme and Python.
And because it is based on an implementation detail (as you say, it is
only *typical*, not mandatory, for Pascal inner functions to be
implemented this way), we have to consider what happens if we come
across a Pascal implementation which *doesn't* use a (code_address,
frame_pointer) pair. Is that no longer Pascal?
This is the interesting, and frustrating, thing about definitions:
deciding where the boundaries lie, and we could argue the boundaries
for days without getting anywhere :-)
--
Steve
More information about the Python-ideas
mailing list