Giter Site home page Giter Site logo

Comments (10)

bakkot avatar bakkot commented on July 30, 2024

There isn't really much interaction. You can't even attempt to access a private field outside of the class in which it's defined - it is a SyntaxError to try.

So:

class Base {
  #f;
}
class Derived extends Base {
  m() {
    this.#f; // SyntaxError: #f is not defined
  }
}

As in other languages, you can have a private field in a derived class of the same name as a private field in a base class, and it will "just work":

class Base {
  #f = 0;
  baseMethod() {
    console.log(this.#f);
  }  
}

class Derived extends Base {
  #f = 1;
  derivedMethod() {
    console.log(this.#f);
  }
}

const instance = new Derived();
instance.baseMethod(); // 0
instance.derivedMethod(); // 1

There is not, in this proposal, any first-class notion of "protected", or of "readonly".

You can use Symbols for something kind of like protected fields:

const p = Symbol();
class Base {
  [p] = 0;
}
class Derived extends Base {
  m() {
    console.log(this[p]); // 0
  }
}

though of course these are accessible to other code via Object.getOwnPropertySymbols.

For "readonly" fields, you may be able to use a decorator, or you can use a getter:

"use strict";
class A {
  get v() {
    return 1;
  }
}
(new A()).v = 2; // TypeError: cannot set property 'v' of [object Object]

from proposal-class-fields.

sugendran avatar sugendran commented on July 30, 2024

Having worked in some very large codebases these features are something I'm keen on. I don't really care about access through getOwnPropertySymbols or iterating over private/public fields via some sort of reflection. What I do care about is how developers signal intent to each other.

The use of the symbols could certainly make protected fields a possibility, but it would be nice to have some syntactic sugar for it.

'readonly' is an interesting one. Yes we can do it with getters. In the C# sense readonly means that the value can only be set in the constructor or field initialiser. This is a great way to signal that this value is meant to be immutable.

I'm not sure if the following is possible, but I guess this is how we'd do readonly using decorators.

class A {
  @readonly v;
  constructor(n) {
     this.v = n;
  }
}

becomes

class A {
  #v;
  get v() {
    return #v;
  }
  constructor(n) {
    this.#v = n;
  }
}

from proposal-class-fields.

sugendran avatar sugendran commented on July 30, 2024

I did try to come up with an example of how protected could work, but I don't really like it. Also the use of this[a] is really not intuitive.

// approach 1 - using an internal class with getters and setters to make the experience a little better
const a = Symbol();
// exported outside the library
class Base {
  [a] = 0;

  addVal(val) {
    this[a] = this[a] + val;
  }

  addVal2(val) {
    this[a] += val;
  }
}

// internal - not exported outside the library
class InternalBase {
  get a() { return this[a]; }
  set a(val) { this[a] = val; }
}

class Derived extends InternalBase {
  m(b) {
    this.a = this.a * b;
  }
}

from proposal-class-fields.

littledan avatar littledan commented on July 30, 2024

We discussed whether private fields should be accessible outside the class that way at length in tc39/proposal-private-fields#33 . The conclusion was to maintain a strong privacy boundary.

from proposal-class-fields.

sugendran avatar sugendran commented on July 30, 2024

Yeah, I tried reading that thread originally and had to stop when it spiraled out of control. Just did my third pass of it.

Was there further/offline discussion of @wycats proposal around adding a "secret" property for decorators? (tc39/proposal-private-fields#33 (comment))

If the decorators supported the "secret" property then you could implement private/protected members using symbols and decorators. Would it not be simpler than adding a private field slot?

And if you didn't want to add the 'secret' option then we just need to make the symbol not iterable, and we could achieve the same outcome.

from proposal-class-fields.

littledan avatar littledan commented on July 30, 2024

There was some further offline discussion. My impression of the end result is that both cases seem to have some use, but there's definitely a lot of use for the secret case, and we ended up taking the side of secret as the default. Decorators' integration with private fields (and methods) to allow a non-secret decorator is a major goal of decorators/private/fields integration. Maybe @wycats could say more.

from proposal-class-fields.

sugendran avatar sugendran commented on July 30, 2024

I see the addition of a 'secret' or 'hidden' property to the decorators negating the need for private fields. Something like:

function private(target, key, descriptor) {
  descriptor.secret = true;
  descriptor.enumerable = false;
}

const field = new Symbol()
class Foo {
   @private [field] = "123";
}

Then a protected field is just one where you have access to the Symbol.

from proposal-class-fields.

littledan avatar littledan commented on July 30, 2024

@sugendran It's unclear to me how this would work. Could you elaborate?

from proposal-class-fields.

sugendran avatar sugendran commented on July 30, 2024

My understanding of the private fields proposal is that we want private fields but we need to satisfy that:

  1. A derived class should not unintentionally overwrite the property of a base class
  2. A derived class should be prevented from knowing/accessing private properties on the base class
  3. A private property should be hidden from getOwnPropertySymbols and getOwnPropertyNames

1 and 2 can be satisfied if the property is a Symbol. A derived class would only be able to access the property using the Symbol, so it has be a deliberate choice on the developer to allow that to happen.

3 can be satisfied if we say that setting 'secret' to true on the descriptor prevents it from being listed in getOwnPropertySymbols and getOwnPropertyNames

from proposal-class-fields.

littledan avatar littledan commented on July 30, 2024

"secret" symbols were rejected in the ES6 cycle, since it was unclear how to explain why they don't hit Proxy traps (and, if they don't hit Proxy traps, what are proxies really good for?). This proposal uses private names instead, which are not properties at all.

I'm closing this issue for now; feel free to reopen if there's a new idea for how to square that circle.

from proposal-class-fields.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.