proposal-grouped-and-auto-accessors icon indicating copy to clipboard operation
proposal-grouped-and-auto-accessors copied to clipboard

Support changing the backing field used by auto-accessors

Open zaygraveyard opened this issue 1 year ago • 8 comments

Reopening https://github.com/tc39/proposal-decorators/issues/511 here as suggested by @pzuraq in this comment.

The README of the decorators proposal stats that the getter and setter defined by the auto-accessors "default to getting and setting a value on a private slot.", so why not allow the use of a different backing field?

The suggestion

Allow accessor to take the backing field name as parameter: accessor(fieldName) accessorName.

accessor(#x) x = 1; would be equivalent to accessor x = 1; except that with the former #x would be accessible syntactically in the class.

The following example would be valid:

class C {
  accessor(#x) x = 1;

  method() {
    this.#x = 456;
  }
}

The backing field can also be public for those who want to avoid private class fields:

class C {
  accessor(_x) x = 1;
}

The above would roughly desugar to:

class C {
  _x = 1;
  get x() {
    return this._x;
  }
  set x(val) {
    this._x = val;
  }
}

This would probably also solve #10 as being an alternative to the private getter and setter syntax.

Other alternative

An alternative that would more resemble C# would be (or similar):

class C {
  #x = 1;
  accessor x { get as #x; set as #x; }
}

PS: This is my first time contributing to discussions on TC39 proposals 😅

zaygraveyard avatar Jun 20 '23 15:06 zaygraveyard

That seems like a nice addition, altho i don’t see the value in allowing public properties to be set here - if you want a public property then what’s the point of get/set functions?

ljharb avatar Jun 20 '23 17:06 ljharb

While it may appear that the sole purpose of get/set functions is to provide public access to private properties, I assure you that this is not the case. Accessors have a broader functionality as they facilitate the abstraction of a class or object's internals, including private-by-convention properties, private language properties, and dynamic properties (such as computed properties).

Accessors have several common use cases, such as:

  1. Read-only properties
  2. Lazy-evaluated properties
  3. Input validation when setting a property
  4. Emitting events when the property value changes

These use cases are applicable to both private class fields and private-by-convention public class fields.

Private class fields are intentionally more restricted than public ones (for instance, they are incompatible with use cases requiring "protected" or "package" visibility). Therefore, in certain scenarios where private class fields cannot be utilized, a private-by-convention approach is more suitable.

EDIT:

It occurred to me that I might have misunderstood the point you were trying to make. If you're saying that accessor(_x) x = 1 is mostly the same as x = 1, that would be true only if no decorator is used as the former is an accessor property and the later is a data property.

Please let me know if I'm still missing something.

zaygraveyard avatar Jun 21 '23 09:06 zaygraveyard

Furthermore, allowing non-private names might simplify expanding auto-accessors to work on object literals, as the README states:

Under Consideration: We may consider expanding auto-accessors to work on object literals in the future, however the necessary private name semantics are currently not defined for object literals.

zaygraveyard avatar Jun 21 '23 09:06 zaygraveyard

If an accessor’s backing is a public property then the abstraction is leaky, since anyone can get at the value without going through the getter, or mutate it without going through the setter.

ljharb avatar Jun 21 '23 13:06 ljharb

Absolutely, that's why I called it private-by-convention and it's how we used to do private properties be for private class fields. But as I've mentioned before, some use cases cannot make use of private class fields as they are too restrictive. Until a better alternative exists, private-by-convention are the only option.

Aside: Since one of those restrictions is their incompatibility with proxies (https://github.com/tc39/proposal-class-fields/issues/106), might this be remedied in a future proposal or is it a non-starter?

zaygraveyard avatar Jun 21 '23 13:06 zaygraveyard

I think it’s a nonstarter - it’s not just proxies, it’s anything that depends on the identity of a receiver. One simply can’t wrap something one doesn’t own and expect to be able to have identical semantics.

ljharb avatar Jun 21 '23 13:06 ljharb

Thank you for the clarification 😄

zaygraveyard avatar Jun 21 '23 13:06 zaygraveyard

To provide further clarification, I hold the belief that public field backed auto-accessors should be allowed. Denying their usage would restrict the adoption of auto-accessors to that of private class fields, which would be unfortunate considering the benefits of this feature.

zaygraveyard avatar Jun 21 '23 14:06 zaygraveyard