archives

« Bugzilla Issues Index

#263 — Deprecation of arguments.callee: how to deal with the case of instances of Function constructor?


Early versions of javascript did not allow named function expressions, and for this reason you could not make a recursive function expression.

For example, this syntax worked:

function factorial (n) {
return !(n > 1) ? 1 : factorial(n - 1) * n;
}

[1,2,3,4,5].map(factorial);

but:

[1,2,3,4,5].map(function (n) {
return !(n > 1) ? 1 : /* what goes here? */ (n - 1) * n;
});

did not. To get around this arguments.callee was added so you could do

[1,2,3,4,5].map(function (n) {
return !(n > 1) ? 1 : arguments.callee(n - 1) * n;
});

However this was actually a really bad solution as this (in conjunction with other arguments, callee, and caller issues) make inlining and tail recursion impossible in the general case (you can achieve it in select cases through tracing etc, but even the best code is sub optimal due to checks that would not otherwise be necessary). The other major issue is that the recursive call will get a different this value, eg.

var global = this;
var sillyFunction = function (recursed) {
if (!recursed) { return arguments.callee(true); }
if (this !== global) { alert("This is: " + this); }
else { alert("This is the global"); }
}
sillyFunction();

Anyhoo, EcmaScript 3 resolved this issues by allowing named function expressions. For example:

[1,2,3,4,5].map(function factorial (n) {
return !(n > 1) ? 1 : factorial(n-1)*n;
});

This has numerous benefits

* the function can be called like any other from inside your code
* it does not pollute the namespace
* the value of this does not change
* it's more performant (accessing the arguments object is expensive)

Whoops, just realised that in addition to everything else the question was about arguments.callee.caller, or more specifically Function.caller. At any point in time you can find the deepest caller of any function on the stack, and as I said above looking at the call stack has one single major effect: It makes a large number of optimisations impossible, or much much more difficult. Eg. if you cannot guarantee that a function f will not call an unknown function it is not possible to inline f. Basically it means that any call site that may have been trivially inlinable accumulates a large number of guards, take:

function f (a, b, c, d, e) { return a ? b * c : d * e; }

If the js interpreter cannot guarantee that all the provided arguments are numbers at the point that the call is made, it needs to either insert checks for all the arguments before the inlined code, or it cannot inline the function. Now in this particular case a smart interpreter should be able to rearrange the checks to be more optimal and not check any values that would not be used. However in many cases that's just not possible and therefore it becomes impossible to inline.

But when you use the Function constructor there are not alternatives to argument.callee, so its deprecation could be a bug:

function createPerson (sIdentity) {
var oPerson = new Function("alert(arguments.callee.identity);");
oPerson.identity = sIdentity;
return oPerson;
}

var john = createPerson("John Smith");

john();


See also: https://bugzilla.mozilla.org/show_bug.cgi?id=725398


(changed bug to a Harmony feature request)


An eval call can be used as an alternative to the Function constructor to dynamically construct such self referential functions.


> An eval call can be used as an alternative to the Function constructor to
dynamically construct such self referential functions.

Of course. But eval works in the local context, Function constructor does not. If you want to return a new function from another one, using eval() will create a closure to the calling context, using the Function constructor does not (it implies greater waste of resources).
But, above all, denying to those functions the possibility of calling themselves means making impossible to create recursive functions from a local scope using the Function constructor.
So, what good is the Function constructor??

It is well to warn programmers of the drawbacks of arguments.callee, as is done with the use of eval(). But you would never remove eval() from the language, because in rare cases is vital and the ability to compile new code on the fly is one of the things which make fascinating this language.

Well, I think the same can be said with regard to arguments.callee. In rare cases it is vital.


Take this example: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function#Example

If you have a little time, try to eliminate arguments.callee from the local function oQuery without creating closures...


(In reply to comment #3)
> > An eval call can be used as an alternative to the Function constructor to
> dynamically construct such self referential functions.
>
> Of course. But eval works in the local context, Function constructor does not.

Not if you make it an "indirect eval", see ES5.1 spec. 10.4.1. For example:

var f = (0,eval)("function f() {/*closed over global scope */})");

> If you want to return a new function from another one, using eval() will create
> a closure to the calling context, using the Function constructor does not (it
> implies greater waste of resources).
> But, above all, denying to those functions the possibility of calling
> themselves means making impossible to create recursive functions from a local
> scope using the Function constructor.
> So, what good is the Function constructor??
>
> It is well to warn programmers of the drawbacks of arguments.callee, as is done
> with the use of eval(). But you would never remove eval() from the language,
> because in rare cases is vital and the ability to compile new code on the fly
> is one of the things which make fascinating this language.

You can easily define your own function that does exactly what you want:

function makeFunction(name,arg1.argn,body) {
var src = "(function "+name+"(";
i (arguments.length >2) src += [].slice.call(arguments,1,-1).join(",");
src += "){";
if (arguments.length>1) src += arguments[arguments.length-1];
src += "})";
return (0,eval)(src);
}

>
> Well, I think the same can be said with regard to arguments.callee. In rare
> cases it is vital.


> You can easily define your own function that does exactly what you want:

You are saying that in order to create some custom functions with some custom text we must use eval() instead of the Function constructor.
Ok sirs, the code is yours...

P.S. What good is the Function constructor??


> You can easily define your own function that does exactly what you want: [...]

And how is the abuse of eval in this context better than the utilization of the Function constructor?

The original deprecation of arguments.callee was due to the introduction of named functions, correct? But in the introduction of named functions, the deprecation of anonymous functions did not occur. pincopalla00's is spot on that, just because there are problem areas surrounding this language's capabilities, does not mean the deprecation of its capabilities are the solution. That notion is completely ludicrous.

In the end, bad practices are associated with the abuses of a language's capabilities, not the capabilities themselves. There are many vital and valuable uses for arguments.callee, and while there are dangers and bad practices surrounding its use, there are best practices as well.

The defense being made here is slightly hypocritical in that somehow we should use eval, rather than a perfectly good solution that is already baked into current implementations of JavaScript.

The deprecation and removal of arguments.callee serves no purpose and will only serve to make this more difficult in situations where it is vital and can be used properly. In this case, utilizing eval instead of arguments.callee is a silly recommendation.


I don't have any real opinion on whether arguments.callee should be removed or not. However, I have found one way of solving the problems raised without using eval or arguments.callee.

The following code should allow self-referencing a "build" function using the Function constructor:

var built = new Function("parameter", "self", "return [this, parameter, self.property];");
built.property = true;

var push = Array.prototype.push;
var wrapped = function(parameter){
push.call(arguments, built);
return built.apply(this, arguments);
};

wrapped.call(window, true); // [window, true, true]

This technique should also work with the aforementioned Function example, too. https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function#Example

And while arguments.callee may or may not become deprecated in the future, I think the above code would be "future-proof" either way.


@Thomas Giles

EXERCISE
Look at the following code:

function createPerson (sIdentity) {
var oPerson = new Function("alert(arguments.callee.identity);");
oPerson.identity = sIdentity;
return oPerson;
}

var john = createPerson("John Smith");

john();

Please, translate ONLY the function "createPerson()":

1) avoiding arguments.callee
2) avoiding eval()
3) avoiding closures

Bye


(In reply to comment #9)
> 3) avoiding closures

I can do it using closures, but not without. I am unsure as to why avoiding closures is a requirement, however?


(In reply to comment #10)
> (In reply to comment #9)
> > 3) avoiding closures
>
> I can do it using closures, but not without. I am unsure as to why avoiding
> closures is a requirement, however?

This is a minimalist example. But there are cases in which closures can be very very expensive for the JS engine. Functions created by Function constructor are created in the global scope, so they don't create closures. So, in that example there are not closures. If, for some reasons, you want to do something like that without arguments.callee, you can't. You can ever use eval(): but eval() is more expensive than Function constructor.
A deprecation is a bad deprecation if it reduces the power of a language, I think. I like freedom when I programme.

Bye.


(In reply to comment #11)

@pincopalla00

You say this deprecation reduces the power of the language. But as far as I can see, removing arguments.callee does not stop you from doing anything. You can get exactly the same effect by using closures to wrap around a Function.

I feel the cases where closures cause performance problems, etc., are few and far between. As you mentioned, there are drawbacks to arguments.callee also, so it looks like either are not ideal.

But I think the point of this bug is to discuss how much impact removing arguments.callee would have; what it would stop you from doing, etc. And as far as I can see, it wouldn't stop you from doing anything.


(In reply to comment #12)
> (In reply to comment #11)
>
> @pincopalla00
>
> And as far as I can see, it wouldn't stop you from doing anything.

It will STOP the possibility to create recursive functions using Function constructor within a local scope, for example: the only possibility will become eval().
If you consider it a good idea, it's ok. But you must accept that you are theorizing a kind of constructor not able to create whatever you could create using its literal homologous. There will be differences in "power" between a literal declaration of a function and an instantiation of a function throught its "Function" constructor. It will be the first case of a "halved" constructor in JS: less powerful than its "literal" homologous.
My opinion is that if it is a good idea to deprecate arguments.callee, than it will be a good idea to deprecate also the Function constructor. I'm serious: a constructor in such a bad is embarrassing.

Bye.


(In reply to comment #13)

@pincopalla00

An interesting point... I would, in fact, argue that this has always been the case anyway. You cannot give a "constructed" Function a name, for example, which could also fix this problem. Then you would be able to truly use the same code for a literal and constructed function.

However, constructed functions have never had any sort of scoping abilities, which also has made them unequal to function literals. The way I see it, constructed functions have never and will never be equal to their literal counterparts. So in my opinion, losing arguments.callee wouldn't really change this "balance of power" all that much anyway.


(In reply to comment #14)

@Thomas Giles

> An interesting point... I would, in fact, argue that this has always been the
> case anyway. You cannot give a "constructed" Function a name, for example,
> which could also fix this problem. Then you would be able to truly use the same
> code for a literal and constructed function.

It could be possible to reserve the word "anonymous" in the language as default name for ALL the "constructed" functions, like in SpiderMonkey. But reserving a word like "anonymous" wouldn't be the same thing (or even worse) as to keep "arguments.callee" in the language??

> However, constructed functions have never had any sort of scoping abilities,
> which also has made them unequal to function literals. The way I see it,
> constructed functions have never and will never be equal to their literal
> counterparts. So in my opinion, losing arguments.callee wouldn't really change
> this "balance of power" all that much anyway.

I can flip your point of view, stating, for example, that "constructed" functions have the ABILITY to skip the local scope, directly nestling in the global one. Only eval([…], 0) has the same ABILITY.
It is an important opportunity, in many cases, if I want to avoid closures.

Bye.


(In reply to comment #15)

Sure, I guess you could reserve anonymous, etc... But that wasn't what I was suggesting. I meant something more along the lines of `new Function(name, arg1, arg2..., code);`, letting you name the resulting function when constructing it.

It is true that using a constructed function would remove any possibility of including the scope. I'm not too sure as to why this would be desirable, however? If you don't want to use closures, could you just not use closures? If you want to avoid using scoped variables, could you just not use scoped variables? And what does this have to do with arguments.callee?


I think it's important for a different language reference here because if all you know is JavaScript...

<?php
$query1 = "...;";
$result1 = mysql_query($query1);

if ($result1)
{
$query2 = "...;";
$result2 = mysql_query($query2);

if ($result2)
{
//etc
}
else {mysql_error_report($query2,mysql_error(),__FUNCTION__);}
}
else {mysql_error_report($query1,mysql_error(),__FUNCTION__);}
?>

Here is how I execute SQL queries. Note that when a query is not executed successfully for whatever reason the function's name is DYNAMICALLY passed on. This is extremely easy for me to implement because I don't have to MANUALLY add STATICALLY defined function names for a function that I may later on rename. In fact when I rename things I often do so without ever opening the file to look at it (Advanced Find and Replace). This is one of the ways I get stuff done so I'm not up until 6am every morning working on code, life doesn't allow that. This allows me to remain vigilant for cases of broken queries or failed attempts at SQL injections (since everything is obviously escaped).

The problem with removing arguments.callee is that there is no dynamic way to pass on the function's name. The examples of what can NOT be done in the presence of arguments.callee require two critical questions...

1. Are these REAL WORLD examples or example examples? Just because you can write code that breaks or does something undesirable doesn't mean what you're doing with the code will actually be useful in a real world scenario and thus it negates the point of writing an example example.

2. If using arguments.callee creates a problem in the example examples then why is someone using arguments.callee instead of something else or working to expand the capabilities of ECMAScript?

From my perspective there is no valid reason to deprecate arguments.callee as it reduces the ability to maintain a higher level of quality code. Simply ask yourself this: do we really want to make it more difficult to keep websites from breaking because web developers have no dynamic means of tracking what is happening with their code and thus decide to not fix things because they have only a broken approach to implement error-reporting?


@Thomas Giles posted a function that he didn't think could be handled under this current version.
function createPerson (sIdentity) {
var oPerson = new Function("alert(arguments.callee.identity);");
oPerson.identity = sIdentity;
return oPerson;
}
var john = createPerson("John Smith");
john();

Perhaps I don't understand what he was trying to do, but it seems as though this is easy. This works whether or not you use strict JavaScript. Just create the object first, remove the word "new" (because we don't want the function evaluated yet), replace callee.identity with [this object].identity then assign identity (so that when you reference the function it will return the appropriate value). If you don't assign identity, then an appropriate "undefined" value is instead returned when the function is finally "opened".

function createPerson (sIdentity) {
"use strict";
var oPerson;
oPerson = function() {alert(oPerson.identity);}
oPerson.identity = sIdentity;
return oPerson;
}
//Test
var john = createPerson("John Smith");
var susan = createPerson("Susan Smith");
var mike = createPerson("Mike Jones");

susan(); // returns alert("Susan Smith")
john(); // returns alert("John Smith")
mike(); // returns alert("Mike Jones")

The alerts are returned in the proper order, Susan, John, Mike, so we see that the proper value is appropriately saved.

This works because you can't call an object until you've created that object (you can't do "var x += 5;"), so you first have to create the object and then you can reference the object (+= 5 or object.whatever). So you have to declare the variable and then you can set the variable equal to something that depends on that variable. We still haven't set that property yet, which is why it's in a function, so it won't be resolved until it's called (and which won't be resolved until the function is called).

Then you need to set the identity property that you're going to be referencing when the new createPerson object is called -- you can't set the identity property earlier because the variable has to actually be "something" (and not simply reference an empty space that nothing has been assigned to yet).

So 1) create the variable, 2) assign the variable to the function just like the original had but reference a different variable, 3) set the value that the function will have asked for once the function is later resolved.

This works because people assume that JavaScript is a strict progression from cause to effect, but actually, from a non-linear, non-subjective viewpoint, it's more like a big ball of wibbely wobbely timey wimey stuff, to quote Doctor Who.


(In reply to BartHumphries from comment #18)

I did not post that code, @pincopalla00 did. He (or she) was saying that there was no way of achieving the same effect without using arguments.callee, eval, or closures. I too do not think closures need be avoided, as demonstrated in your comment.


(In reply to Thomas Giles from comment #19)
> (In reply to BartHumphries from comment #18)
> I did not post that code, @pincopalla00 did.

You're right, my apologies. :)


I have another example, where there is no real alternative to using arguments.callee. Assume this general function:

function mixIn(target, source){
for (property in source) {
func = source[property];
if (typeof func === 'function') {
func.hidden = target[property];
target[property] = func;
}
}
}

Used to mixin functionality from one protype to another:

A = function(){};
A.prototype.foo = function() {
return 'A';
}

AMixin = function(){};
AMixin.prototype.foo = function() {
return arguments.callee.hidden.call(this) + 'mix';
}
mixIn(A.prototype, AMixin.prototype);

a = new A();
a.foo(); // -> 'Amix'

(http://jsfiddle.net/11Ldj0fe/)

Exercise: Remove the arguments.callee from the Mixin-Method, but let it still have access to the "overwritten" method, without:
* Polluting the A.prototype-namespace (which would prohibit mixin-chaining: http://jsfiddle.net/wn7mmd9m/)
* Modifying the arguments-list (which would prohibt mixing-in methods from existing prototypes)


(In reply to pascal.bihler from comment #21)

This should work:

> AMixin = function(){};
> var foo = AMixin.prototype.foo = function() {
> return foo.hidden.call(this) + 'mix';
> }
> mixIn(A.prototype, AMixin.prototype);


(In reply to pincopalla00 from comment #9)
> EXERCISE
> Look at the following code:
>
> function createPerson (sIdentity) {
> var oPerson = new Function("alert(arguments.callee.identity);");
> oPerson.identity = sIdentity;
> return oPerson;
> }
>
> Please, translate ONLY the function "createPerson()":
>
> 1) avoiding arguments.callee
> 2) avoiding eval()
> 3) avoiding closures
>
> Bye

Easy:

function createPerson(sIdentity) {
function person() { alert(person.identity); };
person.identity = sIdentity;
return person;
}

This is using exactly what you're supposed to use instead of arguments.callee - a self-referencing named function.

I trust that a self-referencing named function is not a closure (although I don't see why closures are out of the question).

Now can we remove the obviously false claim that this is "impossible" without arguments.callee from the MDN page on arguments.callee?


> Easy:
>
> function createPerson(sIdentity) {
> function person() { alert(person.identity); };
> person.identity = sIdentity;
> return person;
> }

When we can use function declaration or function expression, we will.

So, when we have to use Function constructor, it means we cannot just declare them.

For example, I have a program that dynamically build thousands of functions based on external business logic and on demand. I can eval, or I can new Function. Would you prefer eval?

I also assigned these functions some properties. Now if I want to access these properties, I can't.

There are workarounds, sure. We can bind. We can delegate the construction to minimize closure / eval impact. We can keep arguments.callee and hope for the best.

I understand that arguments.callee is often misused, and removing it is perhaps for the greater good. But I stand by the thought that it has good uses and ES6 is removing it without offering clean solutions.

A solution as simple as Function.create( name, arg1, arg2 ... body ), for example.


@pincopalla

How about this. Would this meet your needs?

function createPerson (sIdentity) {
var oPerson = (new Function("return function me() { console.log(me.identity); };"))();
oPerson.identity = sIdentity;
return oPerson;
}

var p = createPerson("Guy");

p(); // writes "Guy" to the log


(In reply to JRishe from comment #25)
> @pincopalla
>
> How about this. Would this meet your needs?
>
> function createPerson (sIdentity) {
> var oPerson = (new Function("return function me() {
> console.log(me.identity); };"))();
> oPerson.identity = sIdentity;
> return oPerson;
> }
>
> var p = createPerson("Guy");
>
> p(); // writes "Guy" to the log

@JRishe

Quoting from myself:

> 1) avoiding arguments.callee
> 2) avoiding eval()
> 3) avoiding closures

Your example creates closures.

As said before, removing the possibility for a function to call itself looks simply creazy to me.

If the target is *to forbid bad practices with the brute force*, then you should remove also eval() from ECMAScript, which is definitely the most misused function of ES.

Nevertheless, I think that even eval() is an important ability of ES, which a professional programmer is able to not misuse – as well as arguments.callee.

Use *books* for avoiding bad practices! Do not repress able programmers!!

Best


I tend to agree with you here. I am not really sure why arguments.callee should be removed, though I can see that there are plenty of ways of getting the same effects with that feature.


(In reply to pincopalla00 from comment #26)
>
> Quoting from myself:
>
> > 1) avoiding arguments.callee
> > 2) avoiding eval()
> > 3) avoiding closures
>
> Your example creates closures.
>

Could you tell me where the closure is? Are you saying that a named function expression that refers to itself is using a closure? The function name is local to the function's body, so I'm not so sure that this qualifies as a closure.

Weren't you indeed proposing a way to create NFEs via the Function constructor as a way out of all of this?


(In reply to JRishe from comment #28)
> Could you tell me where the closure is? Are you saying that a named function
> expression that refers to itself is using a closure?

No, of course not! The following code is not a closure, despite a named function is referring to itself:

function me () {
alert(me.identity);
}

me.identity = "John";

me();

Referring to itself has nothing to do with closures. Nevertheless, the following examples are all closures:

var closure1 = (new Function("return function me() { alert(me.identity); };"))();

var closure2 = (new Function("return function () { };"))();

var closure3 = (new Function("return function () { alert(\"Hello world!\"); };"))();

var closure4 = (function () {
return function () {
alert("Hello guys!");
};
})();

> The function name is local to the function's body, so I'm not so sure that
> this qualifies as a closure.

As I said, function naming has *nothing to do* with closures

> Weren't you indeed proposing a way to create NFEs via the Function
> constructor as a way out of all of this?

I am asking how a function created via the Function constructor might call itself avoiding strange stuff like closures or whatever else, just like normal functions normally do!
Is that strange to ask why we have to change our programming logic just because a function is *constructed* instead of *declared*?!?


Interesting post from webreflection:

http://webreflection.blogspot.co.at/2009/06/do-not-remove-argumentscallee-part-ii.html


(In reply to pincopalla00 from comment #30)
> Interesting post from webreflection:
>
> http://webreflection.blogspot.co.at/2009/06/do-not-remove-argumentscallee-
> part-ii.html

I would be equally upset if this feature were deprecated. But what is being deprecated is not what you think. There is an 'arguments' PROPERTY in Function. That's what is getting deprecated. Not the 'arguments' object available within any function block.

So every example you have given will remain valid without any change.

Deprecated:
myFunction.arguments

Not Deprecated:
function myFunction(){
var x = arguments;
var y = arguments.callee;
}


(In reply to cmaj from comment #31)

We're talking about arguments.callee, not arguments. In "strict mode", arguments.callee is deprecated. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/callee


(In reply to Thomas Giles from comment #32)
> (In reply to cmaj from comment #31)
>
> We're talking about arguments.callee, not arguments. In "strict mode",
> arguments.callee is deprecated.
> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/
> arguments/callee

I see. I took my info from this page:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments#Properties

As you can see, neither 'arguments' nor 'arguments.callee' is deprecated according to it. Only 'arguments.caller'. And that page is even slightly more recent.

I'm not sure everyone is on the same page. I hope the strict mode behavior is only the result of that kind of confusion.


(In reply to cmaj from comment #33)
> I see. I took my info from this page:
> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/
> arguments#Properties
>
> As you can see, neither 'arguments' nor 'arguments.callee' is deprecated
> according to it. Only 'arguments.caller'. And that page is even slightly
> more recent.
>
> I'm not sure everyone is on the same page. I hope the strict mode behavior
> is only the result of that kind of confusion.

It would seem that this one detail is missing from that page. MDN is not the ultimate authority on the ES language. It's basically just a wiki.

arguments.caller and arguments.callee are BOTH deprecated in strict mode.
The arguments object is NOT deprecated in any mode.

It's in the spec.
http://www.ecma-international.org/ecma-262/5.1/#sec-C
http://www.ecma-international.org/ecma-262/5.1/#sec-10.6


Clarification: I suspect the reason that arguments.caller is listed as deprecated on that MDN page while arguments.callee is not is that arguments.caller is deprecated in SpiderMonkey in ALL modes.
When it existed, arguments.caller was an implementation-specific feature and was never a formally defined ES feature.

Again, from the spec:

> Arguments objects for strict mode functions define non-configurable accessor properties named "caller" and "callee" which throw a TypeError exception on access. The "callee" property has a more specific meaning for non-strict mode functions and a "caller" property has historically been provided as an implementation-defined extension by some ECMAScript implementations. The strict mode definition of these properties exists to ensure that neither of them is defined in any other manner by conforming ECMAScript implementations.


Bulk closing all Harmony bugs. Proposals should be tracked on GitHub. The ES wiki is completely defunct at this point.