-
Notifications
You must be signed in to change notification settings - Fork 107
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
This proposal introduces new metaprogramming concepts on private fields and methods. This document describes the invariants, guarantees and scope of this privacy as a whole, in light of this feature. | ||
|
||
## Private fields and methods are *hidden* | ||
|
||
Previous documentation used the term "hard private" to explain the guarantees, but that term may lead some to false conclusions. Here, we use the term *hidden*, defined as follows: | ||
|
||
> A class element is *hidden* with the syntax `#name`, which makes it inaccessible except to those granted explicit access to it. | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
littledan
Author
Member
|
||
In this proposal, the following mechanisms grant access to hidden elements: | ||
- Being lexically contained inside the place where the hidden element is defined, e.g., `class { #x; method() { this.#x } }`, the body of `method()` can see `#x`. | ||
- Decorating an element, e.g., in `class { @dec #x; #y; }`, `@dec` can see `#x` but not `#y`. | ||
- Decorating a class containing the element, e.g., in `@dec class { #x; #y; }`, `@dec` can see `#x` and `#y`. | ||
|
||
Future proposals may also grant access to hidden elements, but this will always be through a mechanism which is syntactically apparent; implicit access will never be granted. For example, a `protected` contextual keyword could be added to classes which grants access to subclasses, and this access grant would be similar to that which decorators do. | ||
|
||
## Object capability analysis | ||
|
||
Private fields and methods are analogous to a WeakMap. Each hidden class element has an associated Private Name, which can be seen as in 1-1 correspondence with a WeakMap. Just as WeakMaps may be passed around, so can Private Names. Private Names are passed by default to element decorators and class decorators. With this understanding, private class elements can be used to achieve object capability-based security. | ||
|
||
In practice, the ability to decorate hidden class elements is hoped to strengthen, not weaken, encapsulation by making it applicable in more cases, where a strict lexical-scoping-only regime would reduce applicability and force greater use of non-private mechanisms. | ||
|
||
## Invoking decorators without trust | ||
|
||
To invoke a decorator which should not be trusted with private names, it is possible to wrap the decorator so that it will not see Private Names as follows. This technique, of using JavaScript code to achieve isolation goals in conjunction with new JavaScript features by design, is nothing new; for example, Proxy and WeakMap were designed to be combined to build a membrane abstraction. Membranes are a small, trusted JavaScript library which enables interaction with untrusted code, much like this function. | ||
|
||
```js | ||
function restrict(decorator) { | ||
assert(typeof decorator === "function"); | ||
return descriptor => { | ||
assert(descriptor[Symbol.toStringTag] === "Descriptor"); | ||
switch (descriptor.kind) { | ||
case "class": | ||
let elements, privateElements; | ||
for (let i = 0; i < descriptor.elements.length; i++) { | ||
let element = descriptor.elements[i]; | ||
let arr = typeof element.key === "object" ? privateElements : elements; | ||
arr[arr.length] = element; | ||
} | ||
let result = decorator({...descriptor, elements}); | ||
for (let i = 0; i < privateElements.length; i++) { | ||
result.elements[result.elements.length] = privateElements[i]; | ||
} | ||
return result; | ||
case "method": | ||
case "field": | ||
assert(typeof descriptor.key !== "object"); | ||
return decorator(descriptor); | ||
default: | ||
assert(false); | ||
} | ||
} | ||
} | ||
|
||
// Example usage | ||
|
||
@restrict(defineElement("my-element")) | ||
class MyElement { | ||
#x; // will not show up in defineElement | ||
y; // will show up in defineElement | ||
}; | ||
``` |
4 comments
on commit 37c58d0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't line 33 be
let elements=[], privateElemens=[];
? They're never initialized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rdking Yes, it should be. Good catch! PRs welcome.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also thought it had been decided in July that class decorators wouldn't be allowed access to private fields since that severely weakens encapsulation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rdking You're right; this document needs changes. PRs welcome also!
Also unobservable, which is a critical piece.