On Mar 2, 2015, at 3:14 PM, Jason Orendorff wrote:
> On Mon, Mar 2, 2015 at 4:15 PM, Allen Wirfs-Brock <[email protected]>
> wrote:
>> and conversely if we have something like this:
>>
>> class Bar {
>> constructor(n) {this.n=n}
>> static get const() {return 42);
>> op(x) { return new Bar(Bar.const )}
>> };
>>
>> the inner workings of the class would get very screwed up if somebody did:
>> Bar = { };
>
> ...But that would just be a bug in the program. The same thing would
> happen if you overwrote any function or method anywhere with a random
> object. For `new Bar` to stop working at that point is what people
> will *expect*, and I don't think we do programmers any favors by
> mysteriously masking certain kinds of bug for a little while.
>
> My example was something useful, something programmers will do on
> purpose, that goes silently wonky because of the double binding.
I didn't take the time to come up with a real example. But code within a class
body that refers to the containing class is something I have seem many times.
Some of the most common places you see this is in methods (instance or static)
referring to "constants" defined as static properties of the class. Another
place you see it is "static" methods referring to other static methods of the
same class or applying 'new' to their class name. In most of these cases,
there are actually better ways to do the same thing (referring to 'this' from
within static methods, using 'this.constructor' within instance3 method) but
many developer still use the direct name references.
Of course, using 'new this.construtor' internally would also break your logging
wrapper. Which brings us back to what should probably be the major point..
Class are supposed to be abstractions that encapsulate their internal
implementation details. Expecting that sort of wrapper to work an any sort of
general situation is grossly violating that encapsulation.
The unusual/exceptional case is actually wanting to internally refer to that
sort of mutable binding. But if you want to, you can:
let mutableName = class { foo() {new mutableName)}
it just should be the way things normally work.
>
>> the chain of logic I apply for arriving at the specified behavior is:
>>
>> 1) There are many reasons a developer may want to refer to a class from
>> within it's body and the obvious way of doing so should be reliable and
>> tamper-proof.
>
> The reliability benefit is surely offset somewhat by how confusing this is.
Confusing to who? Pretty much everyone I've seen discover the function binding
equivalent (or have it explained to them for the first time) was shocked.
What! 'function fact(n) {return n>1? n*fact(n-1):1}' doesn't necessarily recur
on the same function? that's crazy! is the typical reaction.
Similarly, it would be crazy if:
class Foo {
static makeFoo() {return new Foo}
}
didn't give you a factory method that created instances of Foo.
>
> If we wanted classes to be tamper-proof, then the outer binding would
> be immutable as well. It's not; it's mutable; yet every use case I can
> think of for actually assigning to it is silently broken due to the
> double binding.
We needed global class bindings to be replaceable.
>
> I favor keeping it mutable, because that's useful and JS is the sort
> of language where you're allowed to hack some things. But as long as
> it's mutable there should not also be a second implicit binding seen
> by different code. One declaration creating two bindings + mutability
> = hall of mirrors.
>
>> 2) This behavior of function declarations is actually quite astonishing and
>> if we had a do over on FunctionDeclaration we would probably give it a local
>> name binding just like function expressions (we might fight about it a
>> while, but I'm pretty sure that's where we would end up).
>
> That's precisely what I thought, until I started thinking about what
> it'll actually be like to use this feature as a programmer.
>
> To me, this issue explains why functions are the way they are.
Not my understandings. Function declarations are the way they are because
that's the way they were in May 1995. Function expressions got added in ES3
and added the local name binding for them. But didn't change function
declarations (probably because it would have been a breaking change).
>
>> 3) Class declarations already differ from function declarations in a number
>> of other ways, so class declaration consistency with function declaration on
>> this one arguably buggy behavior is not a particularly strong position.
>
> Sure, if it were purely about matching what functions do for the sake
> of matchiness, I wouldn't be here.
>
> -j
>
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss