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

Commit

Permalink
Merge pull request #110 from bakkot/note
Browse files Browse the repository at this point in the history
Replace readme with notice of move
  • Loading branch information
littledan committed Dec 13, 2017
2 parents 9289f3b + 1b7bfb4 commit 317cfe8
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 139 deletions.
140 changes: 140 additions & 0 deletions OLD_README.md
@@ -0,0 +1,140 @@
## Current status

This proposal has been merged into the [class fields](https://github.com/tc39/proposal-class-fields) proposal. Please see that repository for current status. The rest of this repository is left up as a historical archive.

Note, this historical version of the specification includes the "private field shorthand" feature, where `#x` is shorthand for `this.#x`. That feature has been removed from the [current class fields proposal](https://github.com/tc39/proposal-class-fields), set to be proposed as a possible follow-on. To minimize confusion, shorthand has been removed from this explainer, though it is still present in supporting documents and the specification text.

## ECMAScript Private Fields

### A Brief Introduction

Private field names are represented as an identifier prefixed with the `#` character. Private field definitions create immutable bindings which are lexically confined to their containing class body and are not reified. In the following example, `#x` and `#y` identify private fields whose type is guaranteed to be **Number**.

```js
class Point {

#x;
#y;

constructor(x = 0, y = 0) {
this.#x = +x;
this.#y = +y;
}

get x() { return this.#x }
set x(value) { this.#x = +value }

get y() { return this.#y }
set y(value) { this.#y = +value }

equals(p) { return this.#x === p.#x && this.#y === p.#y }

toString() { return `Point<${ this.#x },${ this.#y }>` }

}
```

Private fields may also have an initializer expression. Private field initializers are evaluated when the constructor's **this** value is initialized.

```js
class Point {
#x = 0;
#y = 0;

constructor() {
this.#x; // 0
this.#y; // 0
}
}
```

### Private State Object Model

#### Private Field Identiers

Each field definition effectively creates a unique internal slot identifer. In the specification mechanics, this is based on a Private Field Identifier value, not accessible to user code, which is associated through an internal slot in the object with a value. The system can be thought of as equivalent to WeakMaps, with the only difference being the (implied) garbage collection semantics--the value for the private field is held alive by the object, even if nothing else points to the Private Field Identifier.

#### Constructors and Field Initialization

Each ECMAScript function object has an internal slot named `[[PrivateFieldDefinitions]]` which contains a possibly-empty list of Private Field Identifiers and initializer expressions. When a class definition is evaluated, the `[[PrivateFieldDefinitions]]` list of the newly created constructor is populated with a Private Field Identifier for each private name definition within the class body. The constructor adds entries to each object's internal slots, associating the Private Field Identifier to the appropriate value, in this list at the following times:

1. For a base class, after the new object is allocated.
1. For a derived class, immediately after the super call returns.

### Syntax

The lexical grammar is extended with an additional token:

```
PrivateName ::
`#` IdentifierName
```

Private field definitions are allowed within class bodies:

```
PrivateFieldDefinition[Yield] :
PrivateName Initializer[In, ?Yield]? `;`
ClassElement[Yield] :
...
PrivateFieldDefinition[?Yield]
```

Each private field definition creates a lexical binding from a private name to a private field WeakMap.

If an initializer is provided, it is run immediately before the **this** value has been bound to the new object. In derived classes, this will occur after the super call is evaluated.

It is a syntax error if there are any duplicate private field definitions.

Member expressions are extended to allow private references:

```
MemberExpression[Yield] :
...
MemberExpression[?Yield] `.` PrivateName
```

A concise member expression syntax also exists, where `#x` is shorthand for `this.#x`.

When such a reference is evaluated, the private name is lexically resolved to a private field WeakMap. The WeakMap is then used to access the field data associated with the object.

If the WeakMap does not contain an entry for the object a TypeError is thrown.

It is an early error if a member expression contains a private name which cannot be statically resolved.

### Frequently Asked Questions ###

**Q**: Why do we have to use a special character in front of the identifier?

**A**: In short, this seems to be the only way that the system can reliably enforce who has access to the private state in a world with fully dynamic type checking and eval. See [this answer](https://github.com/tc39/proposal-private-fields/issues/14#issuecomment-153050837) for a more detailed explanation of options.

**Q**: Why not use a private version of symbols?

**A**: Private symbols were found to not interact well with membranes used to support certain security paradigms. See [this comment](https://github.com/zenparsing/es-abstract-refs/issues/11#issuecomment-65723350) for details.

**Q**: Why aren't private methods in this proposal?

**A**: This proposal attempts to be minimal, but compatible with a follow-on private methods proposal. See [METHODS.md](https://github.com/tc39/proposal-private-fields/blob/master/METHODS.md) for details.

**Q**: How does private state interact with decorators?

**A**: Private field declarations should be analogous to class property declarations in how they work with decorators. See [DECORATORS.md](https://github.com/tc39/proposal-private-fields/blob/master/DECORATORS.md) for a strawman.

**Q**: Should classes be able to have private fields?

**A**: Also a good possible follow-on proposal;, see [STATIC.md](https://github.com/tc39/proposal-private-fields/blob/master/STATIC.md) for details.

**Q**: Can we use `@` rather than `#` for the sigil, like Ruby?

**A**: TC39 considered this question in the September 2016 TC39 meeting and decided to stick with `@` being proposed for decorators for now. One factor in the decision was the ecosystem of users in transpilation who are using `@` for decorators already.

**Q**: Can we reconsider, in the syntax, the decision to do...

**A**: Yes, it's not too late. Two active discussions on syntax are [whether the declaration should have the word `private` in it](https://github.com/tc39/proposal-private-fields/issues/53) and [what the token should be for initializing a field](https://github.com/tc39/proposal-class-public-fields/issues/33). However, there are other decisions, such as the need for a sigil, and the inability to use `@` for the sigil, that are set for particular strong reasons described above.

If you have an alternative syntax you'd like to suggest, please read [the FAQ](https://github.com/tc39/proposal-private-fields/blob/master/FAQ.md) and understand the constraints.

**Q**: I have another question about the design of the proposal.

**A**: Check [the FAQ](https://github.com/tc39/proposal-private-fields/blob/master/FAQ.md).
141 changes: 2 additions & 139 deletions README.md
@@ -1,140 +1,3 @@
## Current status
## This proposal has been merged into the [class fields](https://github.com/tc39/proposal-class-fields) proposal.

This proposal has been merged into the [class fields](https://github.com/tc39/proposal-class-fields) proposal. Please see that repository for current status. The rest of this repository is left up as a historical archive.

Note, this historical version of the specification includes the "private field shorthand" feature, where `#x` is shorthand for `this.#x`. That feature has been removed from the [current class fields proposal](https://github.com/tc39/proposal-class-fields), set to be proposed as a possible follow-on. To minimize confusion, shorthand has been removed from this explainer, though it is still present in supporting documents and the specification text.

## ECMAScript Private Fields

### A Brief Introduction

Private field names are represented as an identifier prefixed with the `#` character. Private field definitions create immutable bindings which are lexically confined to their containing class body and are not reified. In the following example, `#x` and `#y` identify private fields whose type is guaranteed to be **Number**.

```js
class Point {

#x;
#y;

constructor(x = 0, y = 0) {
this.#x = +x;
this.#y = +y;
}

get x() { return this.#x }
set x(value) { this.#x = +value }

get y() { return this.#y }
set y(value) { this.#y = +value }

equals(p) { return this.#x === p.#x && this.#y === p.#y }

toString() { return `Point<${ this.#x },${ this.#y }>` }

}
```

Private fields may also have an initializer expression. Private field initializers are evaluated when the constructor's **this** value is initialized.

```js
class Point {
#x = 0;
#y = 0;

constructor() {
this.#x; // 0
this.#y; // 0
}
}
```

### Private State Object Model

#### Private Field Identiers

Each field definition effectively creates a unique internal slot identifer. In the specification mechanics, this is based on a Private Field Identifier value, not accessible to user code, which is associated through an internal slot in the object with a value. The system can be thought of as equivalent to WeakMaps, with the only difference being the (implied) garbage collection semantics--the value for the private field is held alive by the object, even if nothing else points to the Private Field Identifier.

#### Constructors and Field Initialization

Each ECMAScript function object has an internal slot named `[[PrivateFieldDefinitions]]` which contains a possibly-empty list of Private Field Identifiers and initializer expressions. When a class definition is evaluated, the `[[PrivateFieldDefinitions]]` list of the newly created constructor is populated with a Private Field Identifier for each private name definition within the class body. The constructor adds entries to each object's internal slots, associating the Private Field Identifier to the appropriate value, in this list at the following times:

1. For a base class, after the new object is allocated.
1. For a derived class, immediately after the super call returns.

### Syntax

The lexical grammar is extended with an additional token:

```
PrivateName ::
`#` IdentifierName
```

Private field definitions are allowed within class bodies:

```
PrivateFieldDefinition[Yield] :
PrivateName Initializer[In, ?Yield]? `;`
ClassElement[Yield] :
...
PrivateFieldDefinition[?Yield]
```

Each private field definition creates a lexical binding from a private name to a private field WeakMap.

If an initializer is provided, it is run immediately before the **this** value has been bound to the new object. In derived classes, this will occur after the super call is evaluated.

It is a syntax error if there are any duplicate private field definitions.

Member expressions are extended to allow private references:

```
MemberExpression[Yield] :
...
MemberExpression[?Yield] `.` PrivateName
```

A concise member expression syntax also exists, where `#x` is shorthand for `this.#x`.

When such a reference is evaluated, the private name is lexically resolved to a private field WeakMap. The WeakMap is then used to access the field data associated with the object.

If the WeakMap does not contain an entry for the object a TypeError is thrown.

It is an early error if a member expression contains a private name which cannot be statically resolved.

### Frequently Asked Questions ###

**Q**: Why do we have to use a special character in front of the identifier?

**A**: In short, this seems to be the only way that the system can reliably enforce who has access to the private state in a world with fully dynamic type checking and eval. See [this answer](https://github.com/tc39/proposal-private-fields/issues/14#issuecomment-153050837) for a more detailed explanation of options.

**Q**: Why not use a private version of symbols?

**A**: Private symbols were found to not interact well with membranes used to support certain security paradigms. See [this comment](https://github.com/zenparsing/es-abstract-refs/issues/11#issuecomment-65723350) for details.

**Q**: Why aren't private methods in this proposal?

**A**: This proposal attempts to be minimal, but compatible with a follow-on private methods proposal. See [METHODS.md](https://github.com/tc39/proposal-private-fields/blob/master/METHODS.md) for details.

**Q**: How does private state interact with decorators?

**A**: Private field declarations should be analogous to class property declarations in how they work with decorators. See [DECORATORS.md](https://github.com/tc39/proposal-private-fields/blob/master/DECORATORS.md) for a strawman.

**Q**: Should classes be able to have private fields?

**A**: Also a good possible follow-on proposal;, see [STATIC.md](https://github.com/tc39/proposal-private-fields/blob/master/STATIC.md) for details.

**Q**: Can we use `@` rather than `#` for the sigil, like Ruby?

**A**: TC39 considered this question in the September 2016 TC39 meeting and decided to stick with `@` being proposed for decorators for now. One factor in the decision was the ecosystem of users in transpilation who are using `@` for decorators already.

**Q**: Can we reconsider, in the syntax, the decision to do...

**A**: Yes, it's not too late. Two active discussions on syntax are [whether the declaration should have the word `private` in it](https://github.com/tc39/proposal-private-fields/issues/53) and [what the token should be for initializing a field](https://github.com/tc39/proposal-class-public-fields/issues/33). However, there are other decisions, such as the need for a sigil, and the inability to use `@` for the sigil, that are set for particular strong reasons described above.

If you have an alternative syntax you'd like to suggest, please read [the FAQ](https://github.com/tc39/proposal-private-fields/blob/master/FAQ.md) and understand the constraints.

**Q**: I have another question about the design of the proposal.

**A**: Check [the FAQ](https://github.com/tc39/proposal-private-fields/blob/master/FAQ.md).
Please see that repository for current status. The rest of this repository is left up as a historical archive. The old readme is available [here](OLD_README.md), but will not be kept up to date. Similarly, while the FAQ in this repository will continue to exist as is, it will not be updated; its canonical location incluing any updates is in the [class fields repository](https://github.com/tc39/proposal-class-fields/blob/master/PRIVATE_SYNTAX_FAQ.md).

0 comments on commit 317cfe8

Please sign in to comment.