# private vs static private

**URL:** <https://es.discourse.group/t/private-vs-static-private/1158>\
**Category:** I have questions\
**Created:** [January 11, 2022, 6:07pm UTC](https://es.discourse.group/t/private-vs-static-private/1158 "2022-01-11T18:07:10Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![rdking](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/rdking/32/54_2.png) [@rdking](https://es.discourse.group/u/rdking)\
**Post date:** [January 11, 2022, 6:07pm UTC](https://es.discourse.group/t/private-vs-static-private/1158/1 "2022-01-11T18:07:10Z")

</div>

After figuring out the best way of working around the known footguns of private fields, I shot myself in the foot yet again. Is this supposed to cause an error?

```javascript
class Test {
    static #foo;
    #foo;
}

```

This throws "Uncaught SyntaxError: Identifier '#foo' has already been declared". This is surprising in the face of:

```javascript
class Test {
    static foo;
    foo;
}

```

having no issues. While I'm not saying I don't understand why this might be (something to the effect of private field names belonging to the class itself regardless of whether or not they're static). However, I **am** saying that this is surprising and unexpected behavior.

The problem here is that although all the private names for a class are kept in the same bucket, and therefore cannot duplicate, this makes no sense in the face of examples like this:

```javascript
class Test {
   static #foo;
   #bar;

   test() {
      try {
      console.log(`Test.#bar = ${Test.#bar}`);
      } catch(e) { console.log(e); }
      try {
      console.log(`this.#foo = ${this.#foo}`);
      } catch(e) { console.log(e); }
   }
}

```

Since the static private field name will only create a slot on the constructor and the instance private field name will only create a slot on instances, it makes absolutely no sense to group both name pools together under a single unique constraint.

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [January 11, 2022, 6:27pm UTC](https://es.discourse.group/t/private-vs-static-private/1158/2 "2022-01-11T18:27:25Z")

</div>

Yes, this is intentional, since each private name is distinct.

If it were permitted, how would you know whether `obj.#foo` is the static or the instance field? Public fields just create properties, and properties don't have this problem because their names aren't a statically known thing like PrivateNames are.

---

<div class="post-metadata">

**Author:** ![senocular](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/senocular/32/642_2.png) [@senocular](https://es.discourse.group/u/senocular)\
**Post date:** [January 11, 2022, 6:35pm UTC](https://es.discourse.group/t/private-vs-static-private/1158/3 "2022-01-11T18:35:34Z")

</div>

[Proposal discussion: Static private member with same private name as a private instance member](https://github.com/tc39/proposal-static-class-features/issues/47)

> Yes, this was on purpose. I didn't see any important use cases, and allowing name sharing would increase complexity a lot.

---

<div class="post-metadata">

**Author:** ![rdking](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/rdking/32/54_2.png) [@rdking](https://es.discourse.group/u/rdking)\
**Post date:** [January 11, 2022, 6:56pm UTC](https://es.discourse.group/t/private-vs-static-private/1158/4 "2022-01-11T18:56:54Z")

</div>

This is yet another one of those cases that makes me wish I was a TC39 member. The solution to this problem is simple. If there is to be a static and instance private field with the same identifier in the the same class, then just make the private name the same. There's no conflict or issue with doing so that I'm aware of, and it doesn't violate any of the demands that I'm aware of that were exposed in the many discussions had in the github repo. So why not just do that?

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [January 11, 2022, 7:10pm UTC](https://es.discourse.group/t/private-vs-static-private/1158/5 "2022-01-11T19:10:24Z")

</div>

That would be a surprising footgun for when someone wanted them to be different.

Additionally, an object can have both static and instance fields via the return override trick; what would happen then?

---

<div class="post-metadata">

**Author:** ![rdking](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/rdking/32/54_2.png) [@rdking](https://es.discourse.group/u/rdking)\
**Post date:** [January 11, 2022, 7:27pm UTC](https://es.discourse.group/t/private-vs-static-private/1158/6 "2022-01-11T19:27:18Z")

</div>

I get the problem. The surprise to me (which at this point shouldn't be surprising given the other choices made in this proposal) is that once again, TC39 prioritized the edge cases over the primary case. It's more common by far and large to have a property of the same name on 2 different objects than it is to have 2 properties of the same name on the same object (especially since that's impossible).

As such, the return override trick would indeed do something somewhat surprising in that case, but far more understandable and inline with how properties work, by overwriting the previously declared private field with the new value since the names would match. If you think about it, this is no different than feeding an already initialized instance to another function of the same class that can change the values. That would be a reasonable outcome.

---

<div class="post-metadata">

**Author:** ![aclaymore](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/aclaymore/32/501_2.png) [@aclaymore](https://es.discourse.group/u/aclaymore)\
**Post date:** [January 11, 2022, 8:41pm UTC](https://es.discourse.group/t/private-vs-static-private/1158/7 "2022-01-11T20:41:00Z")

</div>

It would throw right? If an object already has a private field installed, trying to install the field again throws.

```javascript
class X extends (class { constructor(v) { return v} }) {
   #x;
}
let o = {};
new X(o);
new X(o); // Uncaught TypeError: Cannot initialize #x twice on the same object

```

---

<div class="post-metadata">

**Author:** ![aclaymore](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/aclaymore/32/501_2.png) [@aclaymore](https://es.discourse.group/u/aclaymore)\
**Post date:** [January 11, 2022, 8:50pm UTC](https://es.discourse.group/t/private-vs-static-private/1158/8 "2022-01-11T20:50:13Z")

</div>

@rdking , the [issue](https://github.com/tc39/proposal-static-class-features/issues/47) linked above by @senocular does mention:

> **And** , if it's a syntax error now (as it is), that means if there's a strong use case for it later, it can be added later.

Did you have particular use cases in mind? I imagine most code would know if it's reading from the static class vs an instance.

---

<div class="post-metadata">

**Author:** ![rdking](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/rdking/32/54_2.png) [@rdking](https://es.discourse.group/u/rdking)\
**Post date:** [January 11, 2022, 8:57pm UTC](https://es.discourse.group/t/private-vs-static-private/1158/9 "2022-01-11T20:57:17Z")

</div>

There's no specific use case, just a general one. I have a use case, but it's fairly specific to something I'm working on. I've created a small library that provides the ability to share private data between classes. It's based on this thread I started:

> [@A simple way to implement protected](https://es.discourse.group/t/a-simple-way-to-implement-protected/1110):
>
> As much as I utterly hate the recently accepted class fields proposal, it's still somewhat close to what I was hoping for when they started down this path. So instead of sitting back complaining, I've been thinking about how to take the mess that is and make something I consider useful out of it. In my opinion, there's 3 major issues with class fields/private fields: Private fields (internal slots) footgun Proxy Public fields footgun inheritance The utter absence of a protected implementation. …

The trouble came when using it to work on another library. The first library (cfprotected) uses a private field as a container for the shared data. I need both the instance and the static objects to have a shared container. It would be easier if they both had a shared container of the same name. This would make it easier than having to remember 2 different container names. That's how I ran into this issue.

---

<div class="post-metadata">

**Author:** ![aclaymore](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/aclaymore/32/501_2.png) [@aclaymore](https://es.discourse.group/u/aclaymore)\
**Post date:** [January 11, 2022, 9:42pm UTC](https://es.discourse.group/t/private-vs-static-private/1158/10 "2022-01-11T21:42:36Z")

</div>

The following:

```javascript
class C {
  static #f = 'a';
  #f = 'b';

  static getF(v) {
    return v.#f;
  }
}

```

Would be _roughly_ the same as:

> **FieldFactory util**
>
> ```javascript
> function fieldFactory() {
> const {get, set} = class extends (class { constructor(v) {return v} }) {
> #f;
> 
> static get(o) { return o.#f; }
> 
> static set(o, v) {
> if (! (#f in o)) new F(o);
> o.#f = v;
> }
> }
> 
> return {get, set};
> }
> 
> ```

```javascript
class C {
  static #f = fieldFactory();

  static { C.#f.set(this, 'a'); }

  constructor() {
    C.#f.set(this, 'b');
  }

  static getF(v) {
    return C.#f.get(v);
  }
}

```

Would this work in your use case?

---

<div class="post-metadata">

**Author:** ![rdking](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/rdking/32/54_2.png) [@rdking](https://es.discourse.group/u/rdking)\
**Post date:** [January 11, 2022, 10:18pm UTC](https://es.discourse.group/t/private-vs-static-private/1158/11 "2022-01-11T22:18:42Z")

</div>

It's similar, but the notation is far clumsier than I'd like. Just the fact that I'm using private fields at all means I'm already doing some non-ergonomic things just to prevent issues with the code when used with other libraries. As we know, using private fields is an instant footgun when used in combination with non-membrane uses of Proxy (which a lot of useful libraries do).

Here's an example of the code I'm working on:

```javascript
const { share } = CFProtected;
const TagBase = await import("jsapplib/jsTagBase");

export default class Menu extends TagBase {
    static #tagName = "js-menu";
    static #prot = share(Menu, {}); //Duplication #1: static #prot

    static {
        this.#prot.registerTag(this.#tagName);
    }
    static get tagName() { return this.pvt.#tagName; }
    static get observedAttributes() {
        return TagBase.observedAttributes.concat(["caption"]); 
    }

    #htmlCaption = null;
    #prot = share(Menu, { //Duplication #2: instance #prot
        render() {
            let content = window.document.createElement("div");
            content.style = `
                padding-top: 0.125em;    
                padding-bottom: 0.125em;
            `;
            content.appendChild(window.document.createElement("slot"));
            this.pvt.#renderContent(content);
        },
        onCaptionChanged(e) {
            let match = e.detail.newVal.match(/_(\w)/);
            if (match.length > 0) {
                let key = match[1];
                this.pvt.#htmlCaption = e.detail.newVal.replace(`_${key}`, `<u>${key}</u>`);
            }
            else {
                this.pvt.#htmlCaption = e.detail.newVal;
            }
            let label = this.shadowRoot.querySelector("js-label");
            if (label) {
                label.caption = this.pvt.#htmlCaption;
            }
        }
    });

    constructor() {
        super();
        this.pvt.#addEventListener("render", this.pvt.#prot.render);
        this.pvt.#addEventListener("captionChanged", this.pvt.#prot.onCaptionChanged);
    }

    connectedCallback() {
        super.connectedCallback();
    }

    get caption() { return this.getAttribute("caption"); }
    set caption(v) { this.setAttribute("caption", v); }
}

```

The general idea is that `this.#prot` always refers to the protected container regardless of whether `this` is the constructor or the instance. Makes things easy to remember. However, since there's the potential for this class or its instances to be Proxy wrapped, I bind `this.pvt` to `this` during construction so that even after being Proxy wrapped, the class itself doesn't worry about Proxy interference in accessing private fields. Not very ergonomic, but very safe. Can you see why jumping extra hoops just because 2 different contexts cannot have a member of the same name makes things messier?

Sure, I can easily give up on having the consistency of `this.#prot` being the private container, but I don't see why I should have to. I understand the arguments given, but as always regarding the choices behind private fields, I find those arguments wanting for better logic.

---

<div class="post-metadata">

**Author:** ![bergus](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/bergus/32/152_2.png) [@bergus](https://es.discourse.group/u/bergus)\
**Post date:** [January 12, 2022, 7:08am UTC](https://es.discourse.group/t/private-vs-static-private/1158/12 "2022-01-12T07:08:06Z")

</div>

Oh wow, speaking about unexpected things, I would have expected that to throw a `TypeError: Cannot write private member #x to an object whose class did not declare it` already on the first `new X(o)` call. Not that returning `o` from the `super()` constructor would "change" its class from `Object` to `X`. I thought one of the goals of the private member proposal was to allow simple and effective optimisations by preventing them to be dynamically added to arbitrary objects.

---

<div class="post-metadata">

**Author:** ![rdking](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/rdking/32/54_2.png) [@rdking](https://es.discourse.group/u/rdking)\
**Post date:** [January 12, 2022, 12:39pm UTC](https://es.discourse.group/t/private-vs-static-private/1158/13 "2022-01-12T12:39:41Z")

</div>

Doing that would have been deemed surprising as a class constructor just applies its own modifications to whatever is returned by the super-constructor if it can. This is the result of `class` being designed to appear to be syntactic sugar over the pseudo classes people had been manually coding for years instead of as a truly unique means of introducing type construction. Not necessarily the best choice, but not a bad one either. However, it does mean that it's almost irrelevant what other constructors the object returned by `super()` has passed through except for where the previous constructors' initializations prevent the current constructor from initializing.

It was also deemed early on that there was no harm in allowing this since only the methods of the classes in which the object passed through their constructor would ever be able to access those fields. Information you can't reach, see, or even detect exists is the same as not being there, right? (Proxy sits in the corner and laughs.)

---

<div class="post-metadata">

**Author:** ![rdking](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/rdking/32/54_2.png) [@rdking](https://es.discourse.group/u/rdking)\
**Post date:** [January 15, 2022, 6:44am UTC](https://es.discourse.group/t/private-vs-static-private/1158/14 "2022-01-15T06:44:36Z")

</div>

Turns out there's another similar issue with static private. I'm sure it's this way by design given the way things were decided. However, I can't comprehend why this limitation exists and I'm hoping there's at least something that resembles a good reason.

```javascript
class A {
   static #spvt = 'HHGTTG';
   static run() {
      console.log(`this.#spvt = ${this.#spvt}`);
   }
   #pvt = 42;
   run() {
      console.log(`this.#pvt = ${this.#pvt}`);
   }
}

class B extends A { }

B.run()
//TypeError: Cannot read private member #spvt from an object whose class did not declare it

```

I already get that `#spvt` doesn't exist on `B`. What I don't get is what the harm is in allowing the private field lookup to follow the same prototype search rules as properties, and allowing this call to the inherited `run` function to access the private field it is aware of.

---

<div class="post-metadata">

**Author:** ![mhofman](https://avatars.discourse-cdn.com/v4/letter/m/f14d63/32.png) [@mhofman](https://es.discourse.group/u/mhofman)\
**Post date:** [January 15, 2022, 7:08am UTC](https://es.discourse.group/t/private-vs-static-private/1158/15 "2022-01-15T07:08:28Z")

</div>

That one is actually surprising to me. I thought that since B inherits from A, the B object would have the private fields of the A object installed.

---

<div class="post-metadata">

**Author:** ![rdking](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/rdking/32/54_2.png) [@rdking](https://es.discourse.group/u/rdking)\
**Post date:** [January 15, 2022, 7:12am UTC](https://es.discourse.group/t/private-vs-static-private/1158/16 "2022-01-15T07:12:39Z")

</div>

No. I remember that one. It's like the concept of an "own property". If you go looking on an object for a property definition that it inherited, you won't find it without searching the prototype objects. The problem is that for whatever reason, they decided against doing this for private fields. I don't get why.

---

<div class="post-metadata">

**Author:** ![mhofman](https://avatars.discourse-cdn.com/v4/letter/m/f14d63/32.png) [@mhofman](https://es.discourse.group/u/mhofman)\
**Post date:** [January 15, 2022, 7:20am UTC](https://es.discourse.group/t/private-vs-static-private/1158/17 "2022-01-15T07:20:34Z")

</div>

Ha right, A is only the proto of B, so `this.#foo` is somewhat useless for `static` functions, and using the class identifier (`A.#spvt`) is the only valid way then. That makes it cumbersome for anonymous classes. This is indeed unfortunate.

---

<div class="post-metadata">

**Author:** ![rdking](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/rdking/32/54_2.png) [@rdking](https://es.discourse.group/u/rdking)\
**Post date:** [January 15, 2022, 7:30am UTC](https://es.discourse.group/t/private-vs-static-private/1158/18 "2022-01-15T07:30:05Z")

</div>

In the end, this all just reminds me of the biggest issue I had with the proposal: they valued so many other "concerns" before the basic operations and use cases for classes. I'm pretty sure that if @ljharb or @bakkot, or any of the others answer this question, it will end up being another one of those cases where their decision went counter to the more intuitive standard practices for some obscure reason or to satisfy some obscure want. I would just like to know what it is and whether or not it's even reasonable to correct it at this point.

---

<div class="post-metadata">

**Author:** ![aclaymore](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/aclaymore/32/501_2.png) [@aclaymore](https://es.discourse.group/u/aclaymore)\
**Post date:** [January 15, 2022, 9:26am UTC](https://es.discourse.group/t/private-vs-static-private/1158/19 "2022-01-15T09:26:43Z")

</div>

There is this: [GitHub - tc39/proposal-class-access-expressions: ECMAScript class access expressions](https://github.com/tc39/proposal-class-access-expressions)

For accessing the containing class using `class`. So even anonymous classes could access their static fields safely with `class.#f`

---

<div class="post-metadata">

**Author:** ![aclaymore](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/aclaymore/32/501_2.png) [@aclaymore](https://es.discourse.group/u/aclaymore)\
**Post date:** [January 15, 2022, 10:48am UTC](https://es.discourse.group/t/private-vs-static-private/1158/20 "2022-01-15T10:48:18Z")

</div>

Looks like Java has the same restriction in terms of a static and instance field having the same name:

```javascript
class C {
  static private int x = 1;
  private int x = 2;
}

```

output:

```javascript
Main.java:4: error: variable x is already defined in class C
  private int x = 2;

```

[Next page](https://es.discourse.group/t/private-vs-static-private/1158.md?page=2)
