Skip to content

Commit

Permalink
Normative: Use own properties for privateName objects
Browse files Browse the repository at this point in the history
This patch changes PrivateName objects to have a null prototype
and own methods, as described in

#68 (comment)

I'm not sure whether we want to do the change, but I'm writing it up
so that we can think more carefully about whether we want to go in
this direction. This patch is the most concrete, reasonable thing
I can imagine in the direction of more integrity. It's also a relatively
small change vs the previous proposal.

Some results of the change:
- It's not possible to effectively monkey-patch anything in particular
  to intercept private name accesses; you can only change one in
  particular which you already have access to.
- There may be slightly more memory consuption due to the privateName
  objects having more own properties, but not that much, as the methods
  remain not bound to the receiver.

Closes #68
  • Loading branch information
littledan committed Jul 10, 2018
1 parent b741f75 commit 912f98a
Showing 1 changed file with 42 additions and 83 deletions.
125 changes: 42 additions & 83 deletions spec.html
Expand Up @@ -171,7 +171,7 @@ <h1>The ElementDescriptor Specification Type</h1>
</thead>
<tbody>
<tr> <td>[[Kind]]</td> <td>One of `"method"` or `"field"`</td> </tr>
<tr> <td>[[Key]]</td> <td>A Property Key or %PrivateName% object</td> </tr>
<tr> <td>[[Key]]</td> <td>A Property Key or object with a `[[PrivateName]]` internal slot</td> </tr>
<tr> <td>[[Descriptor]]</td> <td>A Property Descriptor</td> </tr>
<tr> <td>[[Placement]]</td> <td>One of `"static"`, `"prototype"`, or `"own"`</td> </tr>
<tr> <td>[[Initializer]]</td> <td>A function or ~empty~. This field can be absent.</td> </tr>
Expand Down Expand Up @@ -449,109 +449,68 @@ <h1>Runtime Semantics: Evaluation</h1>
</emu-clause>

<emu-clause id="sec-private-name-type-and-objects">
<h1>PrivateName Objects</h1>
<h1>privateName Objects</h1>

<emu-note type=editor>
This section refers to <a href="https://tc39.github.io/proposal-class-fields/#sec-private-names">Private Name values</a>, as defined in the class fields proposal.
</emu-note>

<emu-clause id="sec-private-name-objects">
<h1>Private Name Objects</h1>
<emu-clause id="sec-private-name-constructor">
<h1>The %PrivateName% Constructor</h1>
<p>The Private Name constructor is the <dfn>%PrivateName%</dfn> intrinsic object. When %PrivateName% is constructed with `new`, it returns a new object which wraps a Private Name value. The %PrivateName% intrinsic does not have a global name or appear as a property of the global object.</p>
<h1>The %privateName% factory function</h1>
<p>The Private Name factory function is the <dfn>%privateName%</dfn> intrinsic object. When %privateName% is called, it returns a new object which wraps a Private Name value. The %privateName% intrinsic does not have a global name or appear as a property of the global object.</p>

<emu-clause id="sec-private-description" aoid=PrivateName>
<h1>%PrivateName% ( [ _description_ ] )</h1>
<p>When %PrivateName% is called with optional argument _description_, the following steps are taken:</p>
<h1>%privateName% ( [ _description_ ] )</h1>
<p>When %privateName% is called with optional argument _description_, the following steps are taken:</p>
<emu-alg>
1. If NewTarget is *undefined*, throw a *TypeError* exception.
1. If NewTarget is not *undefined*, throw a *TypeError* exception.
1. If _description_ is *undefined*, let _descString_ be *undefined*.
1. Else, let _descString_ be ? ToString(_description_).
1. Let _name_ be NewPrivateName(_descString_).
1. Let _O_ be ? OrdinaryCreateFromConstructor(NewTarget, `"%PrivateNamePrototype%"`, &laquo; [[PrivateName]] &raquo;).
1. Let _O_ be ? ObjectCreate(*null*, &laquo; [[PrivateName]] &raquo;).
1. Set _O_.[[PrivateNameData]] to _name_.
1. Let _desc_ be PropertyDescriptor{ [[Value]]: `"Private Name"`, [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *true* }.
1. Perform ! DefinePropertyOrThrow(_obj_, @@toStringTag, _desc_).
1. Perform ! CreateDataPropertyOrThrow(_obj_, `"get"`, %PrivateNameGet%).
1. Perform ! CreateDataPropertyOrThrow(_obj_, `"set"`, %PrivateNameSet%).
1. Perform ! CreateDataPropertyOrThrow(_obj_, `"description"`, _descString_).
1. Return _O_.
</emu-alg>
</emu-clause>
</emu-clause>

<emu-clause id="sec-properties-of-the-private-name-prototype-object">
<h1>Properties of the %PrivateNamePrototype% Object</h1>
<p>The %PrivateNamePrototype% object is an ordinary object. It is not a %PrivateName% instance and does not have a [[PrivateNameData]] internal slot.</p>
<p>The value of the [[Prototype]] internal slot of the PrivateName prototype object is the intrinsic object %ObjectPrototype%.</p>

<emu-clause id="sec-private-name.prototype.constructor">
<h1>%PrivateName%.prototype.constructor</h1>
<p>The initial value of `PrivateName.prototype.constructor` is the intrinsic object %PrivateName%.</p>
</emu-clause>

<emu-clause id="sec-private-name-get">
<h1>%PrivateName%.prototype.get ( _object_ )</h1>
<p>When invoked, the following steps are taken:</p>
<emu-alg>
1. Let _O_ be the *this* value.
1. Let _pn_ be ? GetPrivateName(_O_).
1. If Type(_object_) is not Object, throw a *TypeError* exception.
1. Return ? PrivateFieldGet(_pn_, _object_).
</emu-alg>
</emu-clause>

<emu-clause id="sec-private-name-set">
<h1>%PrivateName%.prototype.set ( _object_, _value_ )</h1>
<p>%PrivateNameSet% is a per-realm built-in function object. When invoked, the following steps are taken:</p>
<emu-alg>
1. Let _O_ be the *this* value.
1. Let _pn_ be ? GetPrivateName(_O_).
1. If Type(_object_) is not Object, throw a *TypeError* exception.
1. Return ? PrivateFieldSet(_pn_, _object_, _value_).
</emu-alg>
</emu-clause>

<emu-clause id="sec-private-name.prototype.description">
<h1>get %PrivateName%.prototype.description ( )</h1>
<p>The following steps are taken:</p>
<emu-alg>
1. Let _O_ be the *this* value.
1. Let _pn_ be ? GetPrivateName(_O_).
1. Let _desc_ be _pn_'s [[Description]] value.
1. If _desc_ is *undefined*, return the empty string.
1. Otherwise, return _desc_.
</emu-alg>
</emu-clause>

<emu-clause id="sec-private-name.prototype.tostring">
<h1>%PrivateName%.prototype.toString ( )</h1>
<p>The following steps are taken:</p>
<emu-alg>
1. Throw a *TypeError* exception.
</emu-alg>
<emu-note>
Because conversion to a string throws, ToPropertyKey applied to a %PrivateName% object throws as well. This property is important to ensure that Private Names are not incorrectly used by decorators using property access, rather than with their `get` and `set` methods.
</emu-note>
</emu-clause>

<emu-clause id="sec-private-name.prototype-@@tostringtag">
<h1>PrivateName.prototype [ @@toStringTag ]</h1>
<p>The initial value of the @@toStringTag property is the String value `"PrivateName"`.</p>
<p>This property has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *true* }.</p>
</emu-clause>

<emu-clause id="sec-private-name-this-private-name" aoid=ThisPrivateName>
<h1>GetPrivateName ( _O_ )</h1>
<emu-alg>
1. If Type(_O_) is not Object, throw a *TypeError* exception.
1. If _O_ does not have a [[PrivateNameData]] internal slot, throw a *TypeError* exception.
1. Return _O_.[[PrivateNameData]].
</emu-alg>
</emu-clause>
<emu-clause id="sec-private-name-get" aoid="%PrivateNameGet%">
<h1>%PrivateNameGet% ( _object_ )</h1>
<p>When invoked, the following steps are taken:</p>
<emu-alg>
1. Let _O_ be the *this* value.
1. Let _pn_ be ? GetPrivateName(_O_).
1. If Type(_object_) is not Object, throw a *TypeError* exception.
1. Return ? PrivateFieldGet(_pn_, _object_).
</emu-alg>
</emu-clause>

<emu-clause id="sec-properties-of-private-name-instances">
<h1>Properties of PrivateName Instances</h1>
<p>PrivateName instances are ordinary objects that inherit properties from the PrivateName prototype object. PrivateName instances have a [[PrivateNameData]] internal slot. The [[PrivateNameData]] internal slot is the Private Name value represented by this Private Name object.</p>
<emu-clause id="sec-private-name-set" aoid="%PrivateNameSet%">
<h1>%PrivateNameSet%( _object_, _value_ )</h1>
<p>%PrivateNameSet% is a per-realm built-in function object. When invoked, the following steps are taken:</p>
<emu-alg>
1. Let _O_ be the *this* value.
1. Let _pn_ be ? GetPrivateName(_O_).
1. If Type(_object_) is not Object, throw a *TypeError* exception.
1. Return ? PrivateFieldSet(_pn_, _object_, _value_).
</emu-alg>
</emu-clause>

<emu-clause id="sec-private-name-this-private-name" aoid=ThisPrivateName>
<h1>GetPrivateName ( _O_ )</h1>
<emu-alg>
1. If Type(_O_) is not Object, throw a *TypeError* exception.
1. If _O_ does not have a [[PrivateNameData]] internal slot, throw a *TypeError* exception.
1. Return _O_.[[PrivateNameData]].
</emu-alg>
</emu-clause>

</emu-clause>
</emu-clause>

Expand Down Expand Up @@ -658,7 +617,7 @@ <h1>DecorateElement ( _element_, _placements_ )</h1>
1. For each _decorator_ in _element_.[[Decorators]], in reverse list order do
1. Perform RemoveElementPlacement(_element_, _placements_).
1. Let _elementObject_ be ? FromElementDescriptor(_element_).
1. Let _elementFinisherExtrasObject_ be ? Call(_decorator_, *undefined*, « _elementObject_, %PrivateName% »).
1. Let _elementFinisherExtrasObject_ be ? Call(_decorator_, *undefined*, « _elementObject_, %privateName% »).
1. If _elementFinisherExtrasObject_ is *undefined*,
1. Let _elementFinisherExtrasObject_ be _elementObject_.
1. Let _elementFinisherExtras_ be ? ToElementFinisherExtras(_elementFinisherExtrasObject_).
Expand All @@ -682,7 +641,7 @@ <h1>DecorateConstructor ( _elements_, _decorators_ )</h1>
1. Let _finishers_ be a new empty List.
1. For each _decorator_ in _decorators_, in reverse list order do
1. Let _obj_ be FromClassDescriptor(_elements_).
1. Let _result_ be ? Call(_decorator_, *undefined*, « _obj_, %PrivateName% »).
1. Let _result_ be ? Call(_decorator_, *undefined*, « _obj_, %privateName% »).
1. If _result_ is *undefined*, let _result_ be _obj_.
1. Let _elementsAndFinisher_ be ? ToClassDescriptor(_result_).
1. If _elementsAndFinisher_.[[Finisher]] is not *undefined*,
Expand Down

0 comments on commit 912f98a

Please sign in to comment.