archives

« Bugzilla Issues Index

#2068 — Should the method name be added to the method body environment?


There seems to be some uncertainty about whether the name of a method is bound to the function object inside the method body or not.

https://twitter.com/awbjs/status/386690330180874240
https://github.com/google/traceur-compiler/issues/354

For example:

var x = 1;

class C {
x() {
print(typeof x);
}
}

new C().x();

What does the above print? "number" or "function"?

The current draft does not create an immutable binding to the PropertyName for the environment record.


Marking as invalid. There should be no name binding in the lexical scope.


In ES5:

var x = 1;

var o = {
x: function x() {
print(typeof x);
}
}

o.x(); // function

...Which is exactly what I would expect.

ES6:

var x = 1;

var o = {
x() {
print(typeof x);
}
}

o.x(); // number


That would surprise me and if it were an issue in the ES5 code, I would've just renamed one or the other to ensure that "x" wasn't shadowed in the method's body.


Erik, I'm going to reopen this because I don't think enough discussion has gone into the semantics as they are currently specified.


More here: https://github.com/google/traceur-compiler/issues/354#issuecomment-25816117


The question is, given
var o = {
x() {
print(typeof x);
}
}

what is the binding of x with the function body. Should it be equivalent to:
var o = {
x: function x() {
print(typeof x); //x is locally bound to the function object
}
}

or to:
var o = {
x: function () {
print(typeof x); //x binds to any outer scope declarations
}
}

I content that either is a plausible semantics. But we must decide on only one. I think that the no binding equivalences is the better choice for the following reasons:

1) Legacy consistency. We already have a literal property short hand that was introduced in ES5:

var o = {
get x () {
print(typeof x); //x binds to any outer scope declarations
}
}
As defined by ES5, getter and setter functions do not bind the property name as the function name. See http://www.ecma-international.org/ecma-262/5.1/#sec-11.1.5 and note that a scope containing a binding for the property name is not created.

Because there isn't any other strong reason for choosing between the alternative concise method name binding semantics, consistency between concise methods and getter/setter functions is probably enough to drive the decision.

2) Lack of utility. The primary use case for binding the function name is so a function may recursively refer to itself. However, we are talking about concise *methods*. Methods are functions that are intended to be invoked via a property access and typically refer to a 'this' binding. The proper way for a method to recursively invoke itself is via a method invocation:
var o = {
x() {
//refine this
this.x();
}
}
rather than via a direct call. Binding the name of the function is not needed and does not facilitate correct recursive methods.

Based upon these two points I think we should not bind the names of concise methods.


(In reply to comment #5)
> I content that either is a plausible semantics. But we must decide on only
> one. I think that the no binding equivalences is the better choice for the
> following reasons:
>
> 1) Legacy consistency. We already have a literal property short hand that was
> introduced in ES5:
>
> var o = {
> get x () {
> print(typeof x); //x binds to any outer scope declarations
> }
> }
> As defined by ES5, getter and setter functions do not bind the property name as
> the function name. See
> http://www.ecma-international.org/ecma-262/5.1/#sec-11.1.5 and note that a
> scope containing a binding for the property name is not created.
>
> Because there isn't any other strong reason for choosing between the
> alternative concise method name binding semantics, consistency between concise
> methods and getter/setter functions is probably enough to drive the decision.

Yep, this makes sense. I had thought of the get/set case, but dismissed it because I hoped method shorthand was different enough.


>
> 2) Lack of utility. The primary use case for binding the function name is so a
> function may recursively refer to itself. However, we are talking about
> concise *methods*. Methods are functions that are intended to be invoked via a
> property access and typically refer to a 'this' binding. The proper way for a
> method to recursively invoke itself is via a method invocation:
> var o = {
> x() {
> //refine this
> this.x();
> }
> }
> rather than via a direct call. Binding the name of the function is not needed
> and does not facilitate correct recursive methods.
>
> Based upon these two points I think we should not bind the names of concise
> methods.

I agree, these are the arguments that I was looking for earlier, thank you.