Confusion about closures

L

Lasse Reichstein Nielsen

John G Harris said:
<snip>

To sum up :

You can't insist that top-level functions form closures because there is
no evidence that they do. Equally, I can't insist that top-level
functions do not form closures in strict mode because there is no
evidence that they don't.

It's certain that the variable is looked up in the environment where
the function is created (which is the global scope). The variable
isn't dynamic scoped, i.e.:
var a = 42;
function toplevel() { return a; }
function scope() {
var a = 10;
return toplevel();
}
alert(scope()); // alerts 42.

So, in some sense, the function object is a closure (like any first-class
function in a statically scoped language). The function does remember
where to look up its variables, even if it's just remembering that the
scope is trivial.
I'm happy for you to say that top-level functions form closures,
provided you admit that this is for convenience and tidiness.

It describes what they do - but if one doesn't consider the global
object as part of the captured scope chain, but merely as an implicit
default, then top-level functions (not inside with-statements or catch
clauses) will have an empty/trivial captured environment.

I'd still call it a closure. Capturing an empty environment is
different from not capturing one at all. You can't really have first
class functions and static scope without every function value being a
closure - even if it's a trivial one.
You also need to admit that in non-strict mode closures are a little
bit broken (but in a way that will only bother the worst kind of
library).

I'll admit to that, because I don't think mutable environments are
that good an idea to begin with :)

/L
 
R

Ry Nohryb

And sust a small addition: in ES6 runtime resolution will be eliminated
and the global object will be removed from the top of the scope chain.
All bindings will be static (no addition, no removal). It brings a good
optimization of lexical addressing with nearly O(1) efficiency since a
variable is resolved by direct address without any scope chain lookup.

When/if that ever happens in a future ES-Harmony, then your "captured
by reference" statement would finally become true.
 
T

Thomas 'PointedEars' Lahn

Finally I have some time to catch up with old postings before they expire …
On 24.04.2011 23:25, John G Harris wrote:

If all function objects were closures then the following program would
work:

<script type="text/javascript">
a = 42;

function f()
{ alert(a); }

delete a;
f();
</script>

But it doesn't, it says error (at least in an uptodate IE8).

No, it's still the closure, but you've reached the topic of "captured by
reference" and "captured by value". ES implementations is "captured by
reference" in respect that the parent frame is referred by the [[Scope]]
pointer. Accordingly, if something disappear in that frame, it's
reflected at reading from the closure.

No, 'a' isn't "captured by reference", it's that 'a' (the *symbol*
'a') is looked up first in f's context, then in f's outer context,
then in f's outer context's outer context etc up to the global context
(and of course in any intermediate with()s if there were any).

It seems I said the same -- the parent *frame* that's "captured by
reference" and "a" is just a property (in general definition) of that
frame.

"Parent frame is captured by reference" would be a concept that you
invented. Usually the term "frame" means something else, especially in Web
development, and it certainly cannot be captured (except perhaps in a
screenshot). You should not be surprised that invented concepts lead to
misunderstandings, and certainly you should not insinuate malevolence then.
(Wasn't that VK's domain instead?)

The proper term is "scope", as there is a "scope chain" ([[Scope]]) per
Specification. And the scope is not "captured"; it is added to the scope
chain of the local execution context created by the function declaration.
So that the identifier `a', when being resolved against that scope chain,
cannot be found in the scope of the function execution context and must be
looked up in the next (outer) scope in the scope chain, which is the scope
of the global execution context here. There a property is found that has
the same name as the wanted identifier. And after finding that the owner of
the property is the Global Object (or whatever host object might be before
that in the scope chain) the current value of that property is being
retrieved ([[Get]]). Or the property is not found there, (here) because it
has been deleted in the meantime, so that a ReferenceError exception must be
thrown as the identifier resolution algorithm has reached the end of the
scope chain.

So you can see that when simply quoting the Specification and using its
well-defined terms, what really happens here becomes quite clear without any
need to invent potentially erroneous concepts and potentially ambiguous
terminology. That is of even greater importance if one is not a native
speaker of English.


PointedEars
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,075
Messages
2,570,562
Members
47,197
Latest member
NDTShavonn

Latest Threads

Top