From: Johannes Baagoe on
Lasse Reichstein Nielsen :
> Johannes Baagoe :

>> MDC's bone of contention is this:
>>
>> if (0) {
>> function zero() {
>> document.writeln("This is zero.");
>> }
>> }

> It's worth noticing that the above is not valid ECMAScript.
> The content of the if match either FunctionDeclaration or
> FunctionExpression, but neither is allowed at that point
> (FunctionDeclaration because it is not a Statement, but only a
> SourceElement, i.e., it can only occur directly inside a function body
> or at top-level, and FunctionExpression because a StatementExpression
> may not start with "function").

Aha. Now that, I understand. It did seem curious to define functions
conditionally in this `#ifdef`-like way.

> I.e., it's an ECMAScript extension that Mozilla allows it - as a
> "FunctionStatement".

> The other browsers that also allow it are also extending ECMAScript, but
> probably interpret it slightly differently.

I see that 5th ed. addresses the problem: (12)

NOTE Several widely used implementations of ECMAScript are known to
support the use of FunctionDeclaration as a Statement. However there
are significant and irreconcilable variations among the implementations
in the semantics applied to such FunctionDeclarations. Because of
these irreconcilable difference, the use of a FunctionDeclaration
as a Statement results in code that is not reliably portable among
implementations.

IOW, avoid, unless for personal use or strictly controled intranets.
Even there, it is hard to see any real benefit. If different functions
are needed according to flags (say, various versions of an `assert`
function for debugging), assign them to the same variable in conditions
at the start of the code.

[Very clear explanation of when "function foo() {}" is a function
declaration, and when it is a function expression - many thanks !]

>> if the "Identifier opt" part in the definition of FunctionExpression
>> were removed, there would be no ambiguity at all.

> There would also be no easy way to make recursive function
> expressions. Using arguments.callee sucks (both performance-wise
> and readability-wise).

One could assign the function to a variable in the enclosing scope,
but I have to agree that it useful to be able simply to name the
function for the benefit of its internal scope.

--
Johannes
From: Johannes Baagoe on
Scott Sauyet :

> I'm not sure what we're left with now besides terrible hacks like
> the one you presented and rejected.

At this point, I would say:

1. Declare the functions when there is no good reason for using
function expressions. (Mere pursuit of cuteness does not qualify as
a good reason, except for recreational purposes.)

Thus, Richard Cornford's

(function(x) {
function fact(n) {
return n > 0 ? n * fact(n - 1) : 1;
}
return fact(x);
}(21));

2. If function declarations are undesirable (e.g., for didactic
reasons), assign the inner function to a variable in the outer
function's scope:

(function(x) {
var fact = function(n) {
return n > 0 ? n * fact(n - 1) : 1;
}
return fact(x);
}(21));

> [1] http://yura.thinkweb2.com/named-function-expressions/

Very interesting, thanks a lot.

--
Johannes
From: Johannes Baagoe on
Richard Cornford :
>>> Johannes Baagoe :

>>>> If I want to define 21! inline using neither named function
>>>> expressions
>>>> nor function declarations, the best I have come up with is
>>>>
>>>> ((function() {
>>>> return fact = function(n) {return n > 0 ? n * fact(n - 1) :
>>>> 1;};
> ^^^^
> As that - fact - is undeclared there

Ooops! I wonder how long I shall continue to make that mistake again
and again. Allowing undeclared variables is bad IMHO, but making
them *global* by default is even worse. It is one of the things I still
hate in javascript, with semicolon insertion and a few others.

> But then, why not an inner function declaration, as in:-
>
> ((function() {
> function fact(n){
> return n > 0 ? n * fact(n - 1) : 1;
> }
> return fact;
> }())(21));
>
> - or the simpler:-
>
> (function(x) {
> function fact(n){
> return n > 0 ? n * fact(n - 1) : 1;
> }
> return fact(x);
> }(21));

Why not, indeed.

>> I try to figure out whether there are cases
>> where function expressions need be named,

> Which I think must require an example situation where a named function
> expression couldn't be replaced with an inner function declaration (that
> there be a good reason for not doing so), or a very good argument
> against function declarations.

I do have an argument against function declarations : use function
expressions from the very beginning in order to expose students to
the notion of functions as first-class objects, and don't confuse
them with another, more traditional approach at the same time.

Whether it qualifies as "good" is of course debatable, not to mention
"very good". Outside of introductory courses in either javascript or
general programming, it is a non-starter.

--
Johannes
From: Garrett Smith on
Richard Cornford wrote:
> Johannes Baagoe wrote:
>> Garrett Smith :
>>> Johannes Baagoe :
>>
>>>> If I want to define 21! inline using neither named function
>>>> expressions
>>>> nor function declarations, the best I have come up with is
>>>>
>>>> ((function() {
>>>> return fact = function(n) {return n > 0 ? n * fact(n - 1) :
>>>> 1;};
> ^^^^
> As that - fact - is undeclared there is a side effect of creating a

Mentioned yesterday.

| Syntactially, it could do without the excess grouping operator and
| certainly can do without creating a global identifier within a
| function.
--
Garrett
comp.lang.javascript FAQ: http://jibbering.com/faq/
From: Johannes Baagoe on
[supercede]

Ry Nohryb :

> (function (fact) {
> return fact= function (n) {
> return n > 0 ? n * fact(n - 1) : 1;
> };
> })()(21)

Sure, if you don't object to variables (`fact`, in this case) that are
global in the inner function. Stefan Weiss did, so I tried something else.
Personally, I find your proposal fine, except that I don't understand the
`fact` in the first line.

> Note how clearly and unequivocally "()()" reveals two consecutive
> function calls, much more than a muddy "())())".

I'm not sure, I find

(function () {
var fact = function(n) {
return n > 0 ? n * fact(n - 1) : 1;
}
return fact;
}()(21))

at least as clear.

> And "fact" was a global in yours.

Yes, that makes you the third contributor who (quite rightly) points that
out, and I've just noticed that the first to point it out points out that
he pointed it out. I think I have got it by now :)

--
Johannes