How to understand this form (something) (param);

J

John G Harris

(function g () {
window.onload= function f () {};
})();

1.- g() executes and exits.
2.- outside of g's context, window.onload holds a reference to f,
therefore f still exists even after g() has exited.
3.- as f's context includes g's context, neither g's (nor f's) context
can be destroyed/garbage collected.
<snip>

It doesn't work like that.
function f () {}
must be a function expression as it's on the right-hand side of an
assignment. Therefore the identifier f is a name that's local to f. It's
an alias for 'myself' for use when the function wants to call itself. It
cannot be used outside f. The other code in g cannot use the name f to
call the function.

After g has exited, the unload property of window has a value that is a
pointer to a function object. window doesn't have a name for that
function object other than the property name.

To put it another way, window.unload does not hold a reference to f, it
holds a reference to a function object.

Whatever extra code is put into g the value of f cannot be different
each time g is called.

In short, that isn't an example of a closure and ECMAScript doesn't
require it to be treated as one.

John
 
J

Jorge

<snip>

It doesn't work like that.
function f () {}
must be a function expression as it's on the right-hand side of an
assignment. Therefore the identifier f is a name that's local to f. It's
an alias for 'myself' for use when the function wants to call itself. It
cannot be used outside f. The other code in g cannot use the name f to
call the function.

Yes, and ?
After g has exited, the unload property of window has a value that is a
pointer to a function object. window doesn't have a name for that
function object other than the property name.

Yes, and ?
To put it another way, window.unload does not hold a reference to f, it
holds a reference to a function object.

Yes, a reference to (the function named f) function object.
Whatever extra code is put into g the value of f cannot be different
each time g is called.

The symbol f is not defined, does not exist in g's context.
In short, that isn't an example of a closure and ECMAScript doesn't
require it to be treated as one.

Sure, that's why:

(function g () {
window.onload= function f () { alert(g); };
})();

window.onload();

Alerts:

function g() {
window.onload= function f () { alert(g); };
}
 
R

RobG

   <snip>

It doesn't work like that.
   function f () {}
must be a function expression as it's on the right-hand side of an
assignment. Therefore the identifier f is a name that's local to f. It's
an alias for 'myself' for use when the function wants to call itself. It
cannot be used outside f. The other code in g cannot use the name f to
call the function.

After g has exited, the unload property of window has a value that is a
pointer to a function object. window doesn't have a name for that
function object other than the property name.

To put it another way, window.unload does not hold a reference to f, it
holds a reference to a function object.

Whatever extra code is put into g the value of f cannot be different
each time g is called.

In short, that isn't an example of a closure and ECMAScript doesn't
require it to be treated as one.

I would say that it's a closure: the function object created by the
function expression assigned and to window.onload must have the
activation object of the outer function on its scope chain (or at
least appear to).

The fact that no use is made of the closure doesn't matter, it might
even be optimised away by smart compilers, but it's there in the code.
Memory leaks used to caused in IE using functions like:

function foo(el) {
el.onclick = function() { ... };
}

because the function assigned to the onclick handler has a closure to
el, which is a local variable of the foo function, thereby causing a
circular reference. The listener didn't have to actually reference el
(or any other local variable of foo).

The leak was avoided (in this case) by assigning null to el before the
end of the function, breaking the circular reference (but not the
closure):

function foo(el) {
el.onclick = function() { ... };
el = null;
}

I discussed this with Thomas a little while ago:

"this' confusion"
<URL: http://groups.google.com/group/comp.lang.javascript/msg/43a6ede69ea7abef
 
J

Jorge

I would say that it's a closure: the function object created by the
function expression assigned and to window.onload must have the
activation object of the outer function on its scope chain (or at
least appear to).
(...)

That would be so in any case, whether or not assigned to
window.onload. It's a scoping rule that outer function vars be
accessible from within inner functions.
 
J

John G Harris

On Wed, 5 Aug 2009 at 02:29:07, in comp.lang.javascript, Jorge wrote:

That would be so in any case, whether or not assigned to
window.onload. It's a scoping rule that outer function vars be
accessible from within inner functions.

scoping rule !== closure

John
 
J

John G Harris

I would say that it's a closure: the function object created by the
function expression assigned and to window.onload must have the
activation object of the outer function on its scope chain (or at
least appear to).

ECMA 262 says that the javascript implementation can fall back to a
single scope object when the function objects will always use the same
scope information. So, officially it's not a closure even if the
implementation chooses to use the closure machinery.

The fact that no use is made of the closure doesn't matter, it might
even be optimised away by smart compilers, but it's there in the code.
Memory leaks used to caused in IE using functions like:

function foo(el) {
el.onclick = function() { ... };
}

because the function assigned to the onclick handler has a closure to
el, which is a local variable of the foo function, thereby causing a
circular reference. The listener didn't have to actually reference el
(or any other local variable of foo).
<snip>

ECMA 262 says that the observable behaviour shouldn't be different
whether the closure machinery is used or not. Unfortunately, language
standards usually don't include performance and storage hogging in
'observable' behaviour.

John
 
G

Gabriel Gilini

John said:
ECMA 262 says you're wrong.

Could you please refer to the proper section for our better understanding?
That applies to your previous reply as well.

TIA
 
R

RobG

Of course, but the assignment to window.onload is what makes it
available outside the context of the original function and therefore
is necessary (in the example) for the closure to be formed.

Lets get specific:

Case 1:
---------
function foo() {
function bar() {}
bar();
}
foo();

When foo is executed, bar has foo's activation/variable object on its
scope chain. Once foo has returned, there is no persistent reference
to anything inside foo(). Can bar be said to have a closure to foo,
even if it's just for the time the bar is actually executing? I think
the consensus is "no".


Case 2:
---------
var x;
function foo() {
x = function () {
alert('hi');
}
}
foo();
x();

In this case, the anonymous function assigned to x has foo's
activation object on its scope chain (or is given the appearance that
it has). Implementations may optimise it away as there are no
references to foo's local variables, but that can't be counted on. I
think it should be assumed that a closure exists based on the code,
unless it is *known* that it will only be run in an implementation
that doesn't create a closure for this case.


Case 3:
---------
var x;
function foo(n) {
var num = n;
x = function () {
alert(num);
}
}
foo(42);
x();

I don't think there is any doubt that the above is a closure. The
anonymous function has a closure to num (at least) that persists after
foo has executed due to the assignment to x. Again, an implementation
may decide to simply add num as a local variable to the anonymous
function assigned to x, it's impossible to tell how it does it by
looking at results.

The bottom line for me is that the code pattern for cases 2 and 3
indicate a closure, whether one is in fact created by a specific
implementation is usually irrelevant in general discussion, though it
might be of interest sometimes.
 
J

Jorge

(...)
Case 3:
---------
var x;
function foo(n) {
  var num = n;
  x = function () {
    alert(num);
  }}

foo(42);
x();

I don't think there is any doubt that the above is a closure. The
anonymous function has a closure to num (at least) that persists after
foo has executed due to the assignment to x. Again, an implementation
may decide to simply add num as a local variable to the anonymous
function assigned to x, it's impossible to tell how it does it by
looking at results. (...)

If num were a local variable of x() this wouldn't work:

var x, y;
function foo(n) {
var num = n;
x= function () { alert(num); };
y= function () { num++; }
}

foo(42);
x(); -> 42
y();
x(); -> 43
 
J

Jorge

kangax said:
(...)
| Those local variables,
| parameter and function declarations (initially) have the values that
| they had when the outer function returned and may be interacted with
| by the inner function.

"Those local variables, parameter and function declarations" : inner
function declarations are (really just) local vars too:

var external;
(function g (x) {
function f () { }
f= -1;
external= f;
})(27)

external(); //-> TypeError: expression 'external' [-1] is not a
function.

It's not true that "(initially) have the values that they had when the
outer function returned" :

(function g (x) {
window.onload= function f () { alert(x); }
window.onload(); // "initially" Alerts 27
x++;
})(27)

//but x is 28 when the outer function returned:
window.onload(); //->alerts 28

It would be more correct, I think, to say the truth: that outer
functions' vars and parameters are simply shared with inner functions
(in the same way as globals are, only that globals are shared
globally).

Also, when explaining closures, it might be a good idea to point out
that while

var external;
(function outer (x) {
external= function () { alert(x); };
})(27)

external(); //alerts 27

creates a closure, this -instead- does not:

var external;
(function outer (x) {
external= Function('alert(x);');
})(27)

external(); //ReferenceError: Can't find variable: x
 
R

Richard Cornford

It's not true that "(initially) have the values that they had when the
outer function returned" :

Worthwhile points rarely follow form disingenuous editing.

What you have quoted above is preceded by:-

| ... so that it may be executed after the outer function has
returned.
| At which point it still has access to the local variables,
| parameters and inner function declarations of its outer function.

Where "executed after the outer function has returned" and "At which
point" are significant for the meaning of the following text.

Richard.
 
R

Richard Cornford

On Aug 6, 5:05 am, kangax wrote:
So to summarize (please correct me if I miss something), you
say that closure is formed when a function is being instantiated
within another function and is then made available outside of its
enclosing function.

Whether there are any free variables declared in the scope of
enclosing function is considered irrelevant. How inner function
is made available outside of its enclosing function is also
considered irrelevant (it could be a return value (or part of
it); it could be an assignment to a non-local variable; it could
be passed as one of the arguments to another function; or by
other means). Whether inner function is being actually executed
after enclosing function returns is considered irrelevant as well.
<snip>

I am not sure that that last sentence should be included. This is one
place where John G Harris' "scoping rule !== closure" comes in.
Consider a programming language that is exactly like ECMAScript in
every respect except that the named properties of activation/variable
objects that are created during variable instantiation are deleted as
execution contexts are returned from. This is then a language in which
closures don't exist, yet the behaviour of an inner function called
(even very indirectly) before the function that contains it (within
which it was created) returns is identical to what it would be in
ECMAScript. That behaviour is explained by the language's scoping
rules alone and doesn't require closures.

For a closure I think you want to see both a function object _and_ its
environment outliving their normal (minimum, given the uncertain
nature of garbage collection) lifespan.

This is, of course, an arguable position, even a purely philosophical
position. If all the structures and mechanisms that facilitate
closures are in place why shouldn't a closure be considered to exists?
The same goes for the case where you preserve the inner function but
do not employ its environment (no other inner functions, formal
parameters or variables (or no uses of any of them in the inner
function)); if there is no way to determine whether the environment
was preserved (so no consequences either way) is it worth labelling it
a closure just because the necessary mechanism and structures may be
in place?

Earlier someone mentioned the question of whether if tree falls in a
forest, does it still makes a sound if there is nobody around to
perceive it. A pragmatic attitude might suggest that if you have no
way of knowing if/when a tree falls there is little point in expending
any effort worrying about how much noise it may make if it did.

Richard.
 
J

Jorge

<snip>

I am not sure that that last sentence should be included. (...)

The closure *must* exist as long as the reference (to inner function)
because as long as there's a reference it *could* be executed. To be
sure that it won't, its reference count must be 0.
 
R

Richard Cornford

The closure *must* exist as long as the reference (to inner
function) because as long as there's a reference it *could*
be executed. To be sure that it won't, its reference count
must be 0.

At first that reads as a rather VKesque tangent. Once again you edited
out the context that makes sense of my statement. The point I was
addressing was the question of whether a closure should be considered
to exist if the inner function is (only) executed before the execution
context in which it was created returns and never made available
outside of that context.

Richard.
 
J

Jorge

At first that reads as a rather VKesque tangent. Once again you edited
out the context that makes sense of my statement. The point I was
addressing was the question of whether a closure should be considered
to exist if the inner function is (only) executed before the execution
context in which it was created returns and never made available
outside of that context.

As Pascal's inner procedures, that is, not having first-class
functions, you mean ?
Because if functions are first-class a reference could be passed
along... and you'd end up with a function that does not function.
 

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
474,093
Messages
2,570,607
Members
47,226
Latest member
uatas12

Latest Threads

Top