Skip to content
This repository has been archived by the owner on Jan 25, 2022. It is now read-only.

Question about nested classes and shadowing #126

Closed
mheiber opened this issue Aug 30, 2018 · 9 comments
Closed

Question about nested classes and shadowing #126

mheiber opened this issue Aug 30, 2018 · 9 comments

Comments

@mheiber
Copy link

mheiber commented Aug 30, 2018

Nested Classes Example

In the following code:

class A {
    #foo = "A's #foo";
    #bar = "A's #bar";
    method() {
        class B {
            #foo = "B's #foo";
            methodNested(a) {
                console.log('log this.#foo from B', this.#foo);
                console.log('log a.#bar from B', a.#bar);
                console.log('Chrome Canary errors on the next line');
                console.log('log a.#foo from B', a.#foo);
            }
        }
		new B().methodNested(new A());
    }
}
new A().method();

Chrome Canary with experimental JS flags fails on the last console.log:

VM308:11 Uncaught TypeError: Invalid private field 'Symbol()'
    at B.methodNested (<anonymous>:11:52)
    at A.method (<anonymous>:14:11)
    at <anonymous>:17:9

Question

Is Chrome Canary's behavior to spec? Is it the case that B's #foo shadows A's #foo?

@ljharb
Copy link
Member

ljharb commented Aug 30, 2018

Yes, it’s impossible for B to refer to A’s foo in your example.

However, since they’re both private, you can freely rename one of them without it being observable to any consumers.

@jridgewell
Copy link
Member

Chrome’s behavior is correct. B’s #foo is different than A’s #foo, and B’s #foo is not installed on instances of A

@mheiber
Copy link
Author

mheiber commented Aug 30, 2018

@jridgewell I understand that B's #foo is different from A's #foo.B's #bar is also different from A's bar, but B can refer to it because of lexical scoping.

@ljharb why is the shadowing happening? Can you point to part of the spec? I couldn't figure it out. Thanks for your help.

@ljharb
Copy link
Member

ljharb commented Aug 30, 2018

@mheiber it's just that obj.#foo uses whatever the closest #foo is in lexical scope; so there's simply no way to access the outer #foo - just as if you had:

const foo = "A's #foo";
const bar = "A's #bar";
class A {
    get [foo]() { return 1; }
    get [bar]() { return 2; }
    get ["B's foo"]() { throw new Error("A does not have B's foo"); } // implicit with private fields
    method() {
        const foo = "B's foo";
        class B {
            get [foo]() { return 3; }
            get [bar]() { throw new Error('B does not have bar'); } // implicit with private fields
            methodNested(a) {
                console.log('log [foo] from B', this[foo]);
                console.log('log a’s [bar] from B', a[bar]);
                console.log('errors on the next line');
                console.log('log a[foo] from B', a[foo]);
            }
        }
		new B().methodNested(new A());
    }
}
new A().method();

(note that i typed this without trying it in the repl; i'm hoping it will run, but that either way you get the gist)

@mheiber
Copy link
Author

mheiber commented Aug 31, 2018

@ljharb is the relevant part of the spec just 3.9 where it says:

Private Names follow typical lexical scoping logic. This section contains amended algorithms for managing the scope of Private Names.

@littledan
Copy link
Member

I agree with the above analysis. @gsathya I wonder if it's possible to improve the error message here.

@gsathya
Copy link
Member

gsathya commented Sep 6, 2018

Filed https://bugs.chromium.org/p/v8/issues/detail?id=8144. Can you recommend a better error message?

@mheiber
Copy link
Author

mheiber commented Sep 7, 2018

I posted a suggestion in in the Chrome issue tracker: https://bugs.chromium.org/p/v8/issues/detail?id=8144#c3.

See also this Gist with a rough sketch for how to distinguish the ways a.#foo property accesses expressions can fail: https://gist.github.com/mheiber/03ca6b200fdd2121d24674f19fbc5db7#file-error-cases-for-private-names-md. I'm not sure if the sketch is correct.

@mheiber
Copy link
Author

mheiber commented Oct 8, 2018

closing the issue, since the original question is answered

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants