Function declarations in statements

liorean liorean at gmail.com
Fri Mar 16 15:19:40 PDT 2007


According to ES3, function declarations are not legal in statements
and should be syntax errors. However, all browser hosted
implementations allow function declarations in statements, but do it
differently.

JScript compile time initialises the function in surrounding scope
(likewise compile time initialises function expressions binding the
identifier in the surounding scope, instead of the contained scope).
Opera's linear_b compile time initialises. SpiderMonkey run time
initialises when control flow reaches the function declaration.
JavaScriptCore compile time initialise some cases and run time
initialise others.



Now, I don't think any JavaScript developer expects a function
declaration within a loop, a conditional, a catch statment or a with
statement to  be usable before control flow reaches that point.
Especially I don't think they expect that if they declare a function
in an if-statement and again in the else-clause, the else clause will
override the if clause even if the else clause an under no
circumstances be the taken path.


All in all, I think expectations in these cases are that

function functionname(){}

is exactly equal to

var functionname=function functionname(){};




I feel there is no real reason to compile time initialise these - it
doesn't make sense control flow wise, it defies programmer
expectations, and there is no apparent consensus among
implementations.


Is this something ES4 addresses? If not, it would be nice for
programmers if you did, to increase implementation interoperability
and make reality match programmer expectations.




To copy my example cases from my Opera bug report on the issue :
----
A few tests covering all examples I could think of straight away:



var
o=false;
with({o:true}){
function f(){
return o;
}
}
alert('FunDecl in with-smt is run time instantiated? '+f()+' (wanted
answer: true)');


var
usebeforedeclare=typeof fn==='function';
if(true){
function fn(){
return true;
}
}else{
function fn(){
return false;
}
}
alert('FunDecl in if-smt is compile time instantiated:
'+usebeforedeclare+' (wanted answer: false)\nThe correct path is
taken: '+fn()+' (wanted answer: true)');


bogus:{
break bogus;
function fnc(){}
}
alert('FunDecl in labelled statement is compile time instantiated:
'+(typeof fnc==='function')+' (wanted answer: false)');


while(false)
function func(){}
alert('FunDecl in while-smt is compile time instantiated: '+(typeof
func==='function')+' (wanted answer: false)');


for(;false;)
function funct(){}
alert('FunDecl in for-smt is compile time instantiated: '+(typeof
funct==='function')+' (wanted answer: false)');


for(var t in {})
function functi(){}
alert('FunDecl in for..in-smt is compile time instantiated: '+(typeof
functi==='function')+' (wanted answer: false)');


try{}catch(e){
function functio(){}
}
alert('FunDecl in try..catch-smt is compile time instantiated:
'+(typeof functio==='function')+' (wanted answer: false)');
----

I have no idea of the implications of this for typed code (haven't
read the current draft that thoroughly yet), but I still feel there is
no logic to compile time initialising at least the loop, conditional
and with-statement cases. The catch statement and labelled+break
statement cases are less of an issue, though it would again make more
sense with regard to programmer expectations to follow control flow.
-- 
David "liorean" Andersson



More information about the Es4-discuss mailing list