[Harmony classes] method lexical scope for InstancePropertyDefinitions, PrototypePropertyDefinitions?

# Gavin Barraclough (13 years ago)

I was wondering whether there had been any discussion of bringing instance properties defined in the constructor into the lexical scope of methods , such that 'this.' and 'private(this).' overhead could be diminished?

For example, given the following class:

class Box { Box(x, y, z, density) { public x = x; public y = y; public z = z; private density = density; }

public volume()
{
    return this.x * this.y * this.z;
}

public weight()
{
    return this.volume() * private(this).density;
}

}

If instance properties are in scope the methods volume and weight could be written as:

public volume()
{
    return x * y * z;
}

public weight()
{
    return this.volume() * density;
}

Similarly, if prototype property definitions were brought into scope we could omit the 'this.' on the call to volume:

public weight()
{
    return volume() * density;
}

Might this go some way towards resolving the verbosity of the use of private(this), currently listed as an open issue on the classes proposal, since in many methods these could be omitted?

# Brendan Eich (13 years ago)

On Jun 14, 2011, at 2:45 PM, Gavin Barraclough wrote:

For example, given the following class:

class Box { Box(x, y, z, density) { public x = x; public y = y; public z = z; private density = density; }

public volume() { return this.x * this.y * this.z; }

public weight() { return this.volume() * private(this).density;

Remember, private(this) is intentionally-burn-notice straw at this point.

} }

If instance properties are in scope the methods volume and weight could be written as:

public volume() { return x * y * z;

This works for the public instance properties, but IIRC some folks object that it is too easy to make mistakes vs. formal parameters of the same name.

}

public weight() { return this.volume() * density; }

Here's the killer. density is private. Yes, in this case there can be no other density, but the Point equals method that needs to use p at x and p at y or private(p).x and private(p).y to compare to the other (argument) point p must have new notation for referring to the private instance variable of the other maybe-instance.

Same if you had a compareDensity(otherBox) method here.

Given this, putting the private in scope is helpful for self-references but not for other-refs, and it is a bit misleading.

Similarly, if prototype property definitions were brought into scope we could omit the 'this.' on the call to volume:

public weight() { return volume() * density; }

Object != scope. We do not want mutable objects on the scope chain. We don't want any objects on the scope chain, really. This goes for modules too, they are closed for a reason.

Might this go some way towards resolving the verbosity of the use of private(this), currently listed as an open issue on the classes proposal, since in many methods these could be omitted?

Not in the case of private(other). Without static type information for the parameter to equals and methods like it, we need a separate notation for accessing privates.

# Juan Ignacio Dopazo (13 years ago)

On Tue, Jun 14, 2011 at 7:27 PM, Brendan Eich <brendan at mozilla.com> wrote:

Not in the case of private(other). Without static type information for the parameter to equals and methods like it, we need a separate notation for accessing privates.

/be

This is probably a dumb question but... In which case can a private property of another object be accessed?

Juan

# Luke Hoban (13 years ago)

This is probably a dumb question but... In which case can a private property of another object be accessed?

I believe private is expected to be class-private, not instance-private, so examples like this would access privates of objects other than 'this':

class Point { constructor(x,y) { public x = x; public y = y; } public equals(other) { return private(this).x === private(other).x && private(this).y === private(other).y; } }

There may also be cases where 'var that = this' style patterns are needed so that private accesses are via 'that' inside nested closures.

Luke

# Gavin Barraclough (13 years ago)

On Jun 14, 2011, at 3:27 PM, Brendan Eich wrote:

On Jun 14, 2011, at 2:45 PM, Gavin Barraclough wrote:

  return x * y * z;

This works for the public instance properties, but IIRC some folks object that it is too easy to make mistakes vs. formal parameters of the same name.

Understood. It seems unfortunate to me to restrict the language syntax here to dictate what really seems to be an open question of coding style. Choosing to prefix all member property access with 'this.' in an attempt to avoid such mistakes certainly seems a reasonable position for a programmer to take, however I don't think it's clear that this is the only possible correct decision. A devil's advocate argument might be that the unnecessary verbosity this introduces may make the code less readable, and increase the difficulty for a developer to spot bugs. I don't wish to start a debate on what the right style is here; rather to suggest that we shouldn't be taking a position on either side.

It would seem possible that if we stick with the current proposal and member properties are not in lexical scope, then this may be something that would have to be revisited in a later revision of the language, should developers report the syntax to be overly verbose. If this is the route we go down, do you think perhaps it might be worth trying to reserve space in the language such that there would be room for backwards compatible changes here? For example, might there be any value in considering poisoning these Identifiers, such that a resolve of an Identifer matching the name of an instance property from inside a method is a syntax error?

public weight() { return this.volume() * density; }

Here's the killer. density is private. Yes, in this case there can be no other density, but the Point equals method that needs to use p at x and p at y or private(p).x and private(p).y to compare to the other (argument) point p must have new notation for referring to the private instance variable of the other maybe-instance.

Same if you had a compareDensity(otherBox) method here.

Given this, putting the private in scope is helpful for self-references but not for other-refs, and it is a bit misleading.

Well, I guess there is a simple solution to that problem, though it introduces an asymmetry that I'm not sure you'll be keen on. :-)

Within methods on classes, where ever the Identifier on the RHS of a dot access MemberExpression matches the name of a private property defined in the class, we could always assume this this will be a private property access. This would allow private property access with no additional syntax. In cases where it is necessary to access a public property on an object that has a name aliasing a private member on the current class, bracket access syntax could be used (and a programmer could chose to avoid this problem through naming conventions if they wished to do so, e.g. prefix all private instance property names to prevent conflicts with public properties).

On the topic of p at x, p at y, I find that syntax a little weird since the @ sign reads backwards to me - with an @ I naturally expect the property to be on the left, and the thing that owns it on the right. E.g. brendan at mozilla.com - mozilla.com is an object that has a property called brendan. ;-)

Similarly, if prototype property definitions were brought into scope we could omit the 'this.' on the call to volume:

public weight() { return volume() * density; }

Object != scope. We do not want mutable objects on the scope chain. We don't want any objects on the scope chain, really. This goes for modules too, they are closed for a reason.

Just to clarify I'm only proposing bringing methods on the prototype into the lexical scope of a method where they are defined in the class declaration with a PrototypePropertyDefinition; this would be a purely lexical desugaring rather than introducing the prototype object onto the scope chain.

# Brendan Eich (13 years ago)

On Jun 15, 2011, at 7:16 PM, Gavin Barraclough wrote:

On Jun 14, 2011, at 3:27 PM, Brendan Eich wrote:

On Jun 14, 2011, at 2:45 PM, Gavin Barraclough wrote:

 return x * y * z;

This works for the public instance properties, but IIRC some folks object that it is too easy to make mistakes vs. formal parameters of the same name.

Understood. It seems unfortunate to me to restrict the language syntax here to dictate what really seems to be an open question of coding style.

I should have mentioned the same issue that applies to putting the prototype on the scope chain: you're essentially asking for the same trouble here, but with the instance (this) object. The properties may be deleted -- then what does x mean? An outer x binding shining through?

Classes are sugar for prototypal inheritance, including instance properties that are really properties in an object -- not required to be non-configurable.

Choosing to prefix all member property access with 'this.' in an attempt to avoid such mistakes certainly seems a reasonable position for a programmer to take, however I don't think it's clear that this is the only possible correct decision. A devil's advocate argument might be that the unnecessary verbosity this introduces may make the code less readable, and increase the difficulty for a developer to spot bugs. I don't wish to start a debate on what the right style is here; rather to suggest that we shouldn't be taking a position on either side.

Let's ignore the ocnfusion issue, sorry I brought it up. The problem is putting an object on the scope chain.

It would seem possible that if we stick with the current proposal and member properties are not in lexical scope, then this may be something that would have to be revisited in a later revision of the language, should developers report the syntax to be overly verbose.

Developers have to deal with "this." (and "other.") today -- wherefore CoffeeScript's @ operator.

If this is the route we go down, do you think perhaps it might be worth trying to reserve space in the language such that there would be room for backwards compatible changes here? For example, might there be any value in considering poisoning these Identifiers, such that a resolve of an Identifer matching the name of an instance property from inside a method is a syntax error?

So long as these are instance properties and not immutable fields of some kind (we had those for ES4, we called them fixtures -- they were a lot like non-configurable accessor properties are now), we have a prior problem. We cannot reserve as lexical bindings identifiers naming configurable properties on the receiver.

Within methods on classes, where ever the Identifier on the RHS of a dot access MemberExpression matches the name of a private property defined in the class, we could always assume this this will be a private property access.

That would be a big mistake. Not gonna happen. Onerous for common identifiers (consider the canonical "draw" method on Cowboy and Sprite) used differently by different abstractions.

Object != scope. We do not want mutable objects on the scope chain. We don't want any objects on the scope chain, really. This goes for modules too, they are closed for a reason.

Just to clarify I'm only proposing bringing methods on the prototype into the lexical scope of a method where they are defined in the class declaration with a PrototypePropertyDefinition; this would be a purely lexical desugaring rather than introducing the prototype object onto the scope chain.

I don't know what you mean by "lexical desugaring". That suggests rewriting protoMethod in a prototype-enclosed method to be this.protoMethod or some such expression -- bug again, the protoMethod is in general configurable -- it can be deleted. This is not lexical in any sense.