Confusion about closures

D

Dmitry A. Soshnikov

<snip>

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.

Other languages (especially with immutable nature) may use "capture by
value" strategy. Some languages may probably combine both strategies.
In other languages with closures either there are no global variables or
they're accessible everywhere, always, so there is no need for a special
mechanism to capture the globals used by a function.

Yes, the global frame is always accessible, so e.g. in Python global
functions has `None` as their `__closure__` reference.
ECMAScript is different, as usual.

No so, it's completely apparent with the common theory when all
discussing here things are described long time before ES is appeared at all.
Some kinds of global variable can be
deleted and so ought to be preserved by closures.

No, and I hope now it's clear that "capture by reference" rules in this
case.
Thus, either top-level function declarations do not form closures, or
they're always empty closures.

If to take the formal definition of the spec, a global function doesn't
differ from an inner function and in the same way saves [[Scope]].

In practice, yes, there can be optimizations but this optimization is
not so big (just not to allocated the storage for the [[Scope]] pointer
itself since the global frame may always be found). However, the common
implementation IMO is a better argument to implement these functions the
same way and to put the reference to the global frame into the [[Scope]]
-- it's easier to handle functions calls in respect of identifiers
lookup, etc.

Again, by the spec all functions (except those cases with `Function`
functions) are closures. By the implementations, if a function doesn't
use free variables and doesn't use `eval` there's no need to save
[[Scope]] and all its local variables may be allocated on the stack, not
on the heap.

Dmitry.
 
R

Ry Nohryb

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).

If f had a reference to 'a', such a reference would point to a fixed
'a' in a fixed context (or in a fixed with(object)), but that's not
the case, as you can see e.g. in Lasse's hyper didactic example. Study
it.
 
R

Ry Nohryb

On 24.04.2011 23:25, John G Harris wrote:
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).

If f had a reference to 'a', such a reference would point to a fixed
'a' in a fixed context (or in a fixed with(object)), but that's not
the case, as you can see e.g. in Lasse's hyper didactic example. Study
it.
No, and I hope now it's clear that "capture by reference" rules in this
case.
No.

(...)

Dmitry: this may help you: <http://en.wikipedia.org/wiki/
Reference_(computer_science)>

"The concept of reference must not be confused with other values (keys
or identifiers) that uniquely identify the data item, but give access
to it only through a non-trivial lookup operation in some table data
structure."
 
D

Dmitry A. Soshnikov

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.
If f had a reference to 'a', such a reference would point to a fixed
'a' in a fixed context (or in a fixed with(object)), but that's not
the case, as you can see e.g. in Lasse's hyper didactic example. Study
it.

Either I explained not so well, or you didn't understand what I said.
After the explanation above hope it's clear.

I don't understand why should I continue to repeat it over again? And
instead of "thanks for the explanation" to hear sort of "we don't want
to study, it's good for us with self-imagined definition, no matter
correct are they or not, and we don't want that theory you're talking
about (no matter whether it's correct or not), it's JS group". Sorry, I
leave you too with your guesses.

Dmitry.
 
D

Dmitry A. Soshnikov

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).

If f had a reference to 'a', such a reference would point to a fixed
'a' in a fixed context (or in a fixed with(object)), but that's not
the case, as you can see e.g. in Lasse's hyper didactic example. Study
it.
No, and I hope now it's clear that "capture by reference" rules in this
case.
No.

(...)

Dmitry: this may help you:<http://en.wikipedia.org/wiki/
Reference_(computer_science)>

"The concept of reference must not be confused with other values (keys
or identifiers) that uniquely identify the data item, but give access
to it only through a non-trivial lookup operation in some table data
structure."

And don't even hope -- I won't support you with your damned off-topics.
You perfectly know that I'm completely aware about that off-topic you
try to bring and you perfectly know that I even have written a detailed
article on it.

Dmitry.
 
R

Ry Nohryb

And don't even hope -- I won't support you with your damned off-topics.
You perfectly know that I'm completely aware about that off-topic you
try to bring and you perfectly know that I even have written a detailed
article on it.

It's not off-topic: it's just that nothing is being "captured by
reference" as YOU SAY in your über-pendantic posts.

Read (and study) it again:

<http://en.wikipedia.org/wiki/Reference_(computer_science)>

And if you say it too in your "article", fix it because it's wrong.

Thank you.
 
V

VK

Mr. Soshnikov (Dmitry ?), *all* practical use programming languages
are related with each other, some closer and some lesser so forming
language families: because they are creatures of the human mind thus
their abstraction development paths may be very different yet similar
for a deeper look.

French language and German language are both Indo-European family
language so they are both accusative languages as opposed to ergative
languages. They are both morphological languages as opposed to
analytical languages so the relations between words in a sentence are
formally marked by particular endings. On the chosen higher level of
abstraction I can continue amazingly long with how close these
languages are and how can their shared modern features be explained by
the common Proto-Indo-European past.
And still if one decides to learn French it is suggested to use French
books - and German book for learning German respectively. And if one
decides to speak French it is expected to hear the French, not a
*deliberate* mixture of French nouns, German verbs and reconstructed
Proto-Indo-European pronouns.

Amusingly enough (to me at least) some people do think that the latter
would be a fine way of communication. As the result OP's question came
to "hey, guys, is it a function or what?" making RobG sound like an
idiot.
Moreover, original paper is lambda calculus (and the math in general).
Lisp is just an (approximated) implementation of lambda calculus. And JS
is the same as Lisp in this respect.

Again: while talking about Javascript closures we don't give a damn
about lambda calculus, funarg, Lisp, C++ or the Holy Grail. We want to
talk about Javascript closures. Does "lambda calculus (and the math in
general)" define that the whole Activation object of the outer
Javascript function is retained, not just its variables? Where
exactly?
Where the math (or Lisp for that matter) explains the behavior of the
outer arguments object? Will be created in any case, will it be
created only if used by inner, will it be garbage collected by some
"smart GC" engines? What math book should I read?
What does lambda calculus say about outer named function arguments?
What has Lisp to add about named function arguments and their
reflections in arguments?

Again: here is Javascript group. Here we are talking *in Javascript*
about Javascript. If someone speaks broken Javascript it is OK - just
like no one is obligated to be a native English speaker. Yet imagine I
come to a Texas bar like "Listen, guys, my English is bad and I don't
give a sh** about this crappy language anyway. I am a speaker of a way
more superior language and a bearer of a superior cultural behavior".
In this case my chances to leave the bar by head-forward flying become
way more superior than by walking out. Is not it? ;-)

So you were serious to propose it as a definitive usable not saying
casual definition?
- What is a native object?
- http://www.jibbering.com/faq/#nativeObject

- What is a closure?
- a upward funarg with free variables

Or maybe you wanted to tell that in order to program properly in
Javascript one needs to know and to understand the Funarg problem
(http://en.wikipedia.org/wiki/Funarg_problem), the
Entscheidungsproblem, the Turing completeness and so on? Oops, the
guys at the next table left their whisky and started to listen. And I
don't like their faces... :))
 
V

VK

I don't understand why should I continue to repeat it over again? And
instead of "thanks for the explanation" to hear sort of "we don't want
to study, it's good for us with self-imagined definition, no matter
correct are they or not, and we don't want that theory you're talking
about (no matter whether it's correct or not), it's JS group".

If it is a problem to get to a consensus from the bottom it could be
more fruitful to go from the top.

// case 1:

function outer() {

var privateVar = 'foobar';

return inner;

function inner() {
return privateVar;
}

}

var thingy = outer();

window.alert( thingy() ); // 'foobar'


// case 2:

function outer() {

return 'Hello ' + inner();

function inner() {
return 'World!';
}

}

window.alert( outer() ); // 'Hello World!'


// case 3

function outer() {
// and no inner() or other tricks
// simply ol'good JavaScript function
}


Assume and I hope that "case 1, 2, 3 all should be described as
closures, there is no need for other terms" is not an option. However
it could be theoretically/historically/academically proper, it is like
insisting to use the generic "an animal" both for a lion and a rabbit
and to forget the words "a lion" and "a rabbit".
Do we have terms for cases 1, 2, 3? I used to think that the case 1 is
a Javascript closure (the hot topic of what part exactly or all
together is called "closure" we are leaving for latter). I used to
think that case 2 is a Javascript function declaration with a nested
(inner) function in it. I used to think that case 3 is dimply a
Javascript function declaration.
It doesn't matter of course what I used to think. The question is: do
we have a necessity to distinguish cases 1, 2, 3 by different terms
and what such terms would be?
 
R

Ry Nohryb

Dmitry: this may help you: <http://en.wikipedia.org/wiki/
Reference_(computer_science)>

"The concept of reference must not be confused with other values (keys
or identifiers) that uniquely identify the data item, but give access
to it only through a non-trivial lookup operation in some table data
structure."

And this too:

<http://en.wikipedia.org/wiki/Identifier>

"In computer languages, identifiers are tokens (also called symbols)
which name language entities. Some of the kinds of entities an
identifier might denote include variables, types, labels, subroutines,
and packages."
 
L

Lasse Reichstein Nielsen

[Examples]
Assume and I hope that "case 1, 2, 3 all should be described as
closures, there is no need for other terms" is not an option. However
it could be theoretically/historically/academically proper, it is like
insisting to use the generic "an animal" both for a lion and a rabbit
and to forget the words "a lion" and "a rabbit".

Seems more like "No, you can't say a lion is an animal. We used
'animal' for rabbit.".
Do we have terms for cases 1, 2, 3?

1: Returning a closure (or just returning a function, but it being a
closure is important here).

2: Calling a function and returning a string? Seems plain old Javascript
to me.

3: Whatever it does.
I used to think that the case 1 is a Javascript closure (the hot
topic of what part exactly or all together is called "closure" we
are leaving for latter).

There is a closure involved, and its relevant that it's a closure,
so it's reasonable to use the word when describing what's happening.
I used to think that case 2 is a Javascript function declaration
with a nested (inner) function in it.

It is. The inner function is a (trivial) closure, but it's not really
relevant to the behavior, so it's reasonable to omit the word when
describing what is happening.
I used to think that case 3 is dimply a Javascript function
declaration.

Seems so. (Is it intentionally empty?).
It doesn't matter of course what I used to think. The question is: do
we have a necessity to distinguish cases 1, 2, 3 by different terms
and what such terms would be?

We will probably use the word "closure" in the description of case
1, because it matters that the function (like all functions in JS)
is a closure. We won't need it for the other cases, because the
closure-ness isn't relevant to what's happening.

You can avoid using "closure" for case 1, though. It's just a
shorthand to describing a more complex concept with a predefined word.
You could also say that the outer function returns a nested function
that has access to (and returns the value of) a local variable of outer.

/L
 
J

John G Harris

No, it works, exactly as you wrote it.

I usually describe a closure as code combined with an environment
binding the free variables of the code. The variables will be looked
up in that environment when the code is executed.
You have shown (and it is an interesting point) that environments in
Javascript are mutable. The environment can even stop having a binding
for the free variable (just as it could have omitted having one from
the start). The variable is still looked up in that environment, and
exactly because of that, it will now fail to find a binding.

You and Dmitry can't wriggle out of it that easily. You have said that
if a free variable disappears, ceases to exist, then the function using
it should not fail. That's what closures are for.

It doesn't matter if it's difficult to implement. You either have no
closure in the top level function case, or closures are broken in ES.

More importantly, in other languages you can't unbind a variable that
already exists. That is what happens here.

In other words, variables aren't guaranteed to be accessible everywhere,
always, in ES.

I disagree. In another language, that might be what I wanted, but in
Javascript, it would definitly not be proper. The closure maintains
the scope chain that binds the free variables of the function. Any
change to that scope chain should be reflected in the variable lookup
when the function is executed.
<snip>

Scope chains, etc, are implementation details. They don't tell us what
closures ought to do. Nor do they define the meaning of 'free variable'.

John
 
D

Dmitry A. Soshnikov

You and Dmitry can't wriggle out of it that easily. You have said that
if a free variable disappears, ceases to exist, then the function using
it should not fail.

As I said from the beginning, JS uses the model of "chained environment
frames". Which means that exactly a complete frame is closured. In JS
the parent frame is pointed by the [[Scope]] property. However, the
bindings inside the frame may easily change, be removed, etc. Because in
JS closures are mutable.

So again, your assumption with "if a free variable disappears" means for
JS that if the _context_ in which that free variable is defined
_finishes_, then there should be done so that if some of inner functions
uses that variable, they initially after the moment of the parent
context termination, should still be able to use that free variable. But
after that, the free variable may easily dissapear from the parent
frame, e.g. via using `delete` operator.

Note, in this case the variable is still `free` for a function. But in
this case it's became "free unbound variable" (a case of ReferenceError
in JS).

Info:
http://dmitrysoshnikov.com/ecmascri...cal-environments-common-theory/#free-variable

That's what closures are for.

I thought it's already clear that closures are not only for this. It's
only the part of the closures nature (though, as I said, the most
interesting part -- upward funarg).

However, why do you exclude "downward funarg", i.e. when the context of
a free variable may still be alive, but there is ambiguity -- from which
context to use a free variable: from statically saved at the moment of a
function creation, or dynamically formed by the caller? And the answer
is -- of course form statically saved. And this last word "saved"
already assumes that the function saved its lexical environment, and
being a pair of its code and that saved environment it's called a closure.

(function () {

var a = 10;

function foo() {
console.log(a);
}

(function () {
var a = 20;
foo(); // ?
}());

})();

The example should result 10 if the `foo` function is closure. Is it so
in JS? Absolutely.

A closure is for correct lookup of free variables, thus the context of
free variables may still exists (downward funarg) or not (upward funarg).
It doesn't matter if it's difficult to implement. You either have no
closure in the top level function case, or closures are broken in ES.

Other languages, may statically save free bindings. That is, saved
lexical environment is not pointed by some property e.g. [[Scope]], but
it's direct value. In this case of course there can be no case when a
binding is disappeared, it's not accessible from the closure. In JS,
repeat, lexical environment is _referred_ (not a static copy), therefore
bindings are may be though as "capture by reference" (though,
technically just the frame is referred, not exact bindings).

Is it OK now? Is it clear?

Dmitry.
 
L

Lasse Reichstein Nielsen

John G Harris said:
You and Dmitry can't wriggle out of it that easily. You have said that
if a free variable disappears, ceases to exist, then the function using
it should not fail. That's what closures are for.

I'm pretty sure that's not what I have said.

I might, mistakenly, have said that a variable uses the binding that
it had where the function is declared. You have shown that the
explanation needs to take the possibility of a mutable scope into
account. Most other languages don't allow for a binding to disappear
at all, or even the creation of a function referencing a variable
that isn't bound yet.

What is true is that a variable uses the captured scope that was
current where the function was created. The closure is the combination
of code and environment (scope chain).
It doesn't matter if it's difficult to implement. You either have no
closure in the top level function case, or closures are broken in ES.

I think my example shows that the top level isn't special.
You can have appearing and disappearing bindings at any level.

Obviosuly, an implementation may save some steps when it knows that
a function references has only global variables, but again, that's
not specific to top-level functions. You can also have a nested function
that only references global variables.
In other words, variables aren't guaranteed to be accessible everywhere,
always, in ES.

Exactly. Yey, ES! Making implementation difficult since 1995.
Scope chains, etc, are implementation details. They don't tell us what
closures ought to do. Nor do they define the meaning of 'free variable'.

True. Generic words like "scope" and "environment" can be used, but since
the environment is mutable, even if the scope is static, extra care must
be taken (compared to, e.g., Scheme, ML, Haskell or Java).

Javascript has static scope and first class functions, so it needs
closures. However, unlike most other such languages, it has dynamic
variable resolution. Since the variables declared in a scope can
change over time (and a variable can even be unbound when a function
referencing it is creates), it matters *when* a variable is resolved
in a scope. Unlike other languages, it's not just done once.

So, a closure is still the combination of function code and an
environment. The environment is used to resolve any free variables in
the function code, and not just (as would be sufficient in a language
with static variable resolution) used to hold the statically known
bindings of the variables.

/L
 
D

Dmitry A. Soshnikov

Javascript has static scope and first class functions, so it needs
closures. However, unlike most other such languages, it has dynamic
variable resolution.

I'd better use "runtime variable lookup" or yes, "dynamic binding"
(which was confused by some of es-discuss and TC-39 members with
"dynamic scope" as probably you remember).

Since the variables declared in a scope can
change over time (and a variable can even be unbound when a function
referencing it is creates), it matters *when* a variable is resolved
in a scope. Unlike other languages, it's not just done once.

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.

Dmitry.
 
V

VK

a = "outer"; ....
delete a;

"delete" operator cannot be used for Global object properties
(Javascript variables) except some non-conforming implementation.

console.log(a);

This code errors out on IE6-IE8 and older ECMA-compliant browsers.

I would ask the supporters of the "new understanding of Javascript
closures" to use ECMA-262 3rd ed compatible samples with windows.alert
or DOM0 methods for output. If it is not then refrain from saying
"Javascript" or "JS" and use instead the specific implementation data
such as "JavaScript in Firefox X.Y does..." and similar.
Otherwise the discussion - which is already rather nutty - will get
totally crazy with everyone using his own terms, his own term
understanding, his own syntax and his own testing platform.

The same applies to the contra-arguments of course.

no time today to write on the main topic
 
L

Lasse Reichstein Nielsen

VK said:
"delete" operator cannot be used for Global object properties
(Javascript variables) except some non-conforming implementation.

Ofcourse it can.
It won't delete a property that has been declared using a "var"
declaration in the global scope, but it will delete properties
that have been directly set on the global object, including assignments
to undeclared variables. The latter was the case here ("a" was not
declared as a variable).

/L
 
J

John G Harris

Ofcourse it can.
It won't delete a property that has been declared using a "var"
declaration in the global scope, but it will delete properties
that have been directly set on the global object, including assignments
to undeclared variables. The latter was the case here ("a" was not
declared as a variable).

Note that this changes in strict mode, mainly because you aren't allowed
to assign to undeclared variables. (ES5, Annex C, 3rd item)

John
 
J

John G Harris

So, a closure is still the combination of function code and an
environment. The environment is used to resolve any free variables in
the function code,
<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.

I'm happy for you to say that top-level functions form closures,
provided you admit that this is for convenience and tidiness. 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).

John
 
J

John G Harris

So again, your assumption with "if a free variable disappears" means
for JS that if the _context_ in which that free variable is defined
_finishes_, then there should be done so that if some of inner
functions uses that variable, they initially after the moment of the
parent context termination, should still be able to use that free
variable. But after that, the free variable may easily dissapear from
the parent frame, e.g. via using `delete` operator.
<snip>

Have you read what you have just written? Wow!

You're saying that the 'How to make closures work' problem shouldn't be
solved. (And yes, I have read your common theory sub-chapter).

John
 
L

Lasse Reichstein Nielsen

John G Harris said:
Note that this changes in strict mode, mainly because you aren't allowed
to assign to undeclared variables. (ES5, Annex C, 3rd item)

That, and the abolishment of "with" and change to direct calls to
"eval", does make a difference. You can still create the global
property so that it can be deleted later, but you can't introduce new
variables that might shadow it, or remove ones that does (apart from
the prototype chain of the global object)..


This ofcourse only holds if the strict-mode code is top-level. You can
declare strict mode functions inside non-strict functions, so that the
strict mode code runs in a mutable environment:

Example, strict function in mutable environment:

var p = (function scope() {
var global = this;
global.a = "global";
eval("var a = 'inner';");
var o = {a : "with"};
with(o) {
return [function(s){eval(s);}, function() { "use strict"; return a; }];
};
})();
var cheat = p[0];
var geta = p[1];
alert(geta()); // "with"
cheat("delete o.a;");
alert(geta()); // "inner"
cheat("delete a;");
alert(geta()); // "global"
cheat("delete a;");
alert(geta()); // throws ReferenceError


But as I said, the global object is still mutable in strict mode.
Example 2, more strict, still dynamic variable resolution/binding:

"use strict";
var p = (function scope() {
var global = Function("return this")();
global.a = "global";
Object.getPrototypeOf(global).a = "proto";
eval("var a = 'inner';");
return [function cheat(s){eval(s);}, function geta() { return a; }];
})();
var cheat = p[0];
var geta = p[1];
alert(geta()); // "global"
cheat("delete global.a;");
alert(geta()); // "proto"
cheat("delete Object.getPrototypeOf(global).a;");
alert(geta()); // throws ReferenceError

/L
 

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

No members online now.

Forum statistics

Threads
473,997
Messages
2,570,240
Members
46,828
Latest member
LauraCastr

Latest Threads

Top