Skip to content

Commit

Permalink
Add records (open dictionaries). (#180)
Browse files Browse the repository at this point in the history
  • Loading branch information
jyasskin authored and tobie committed Oct 17, 2016
1 parent 9c8aa9b commit 1814384
Show file tree
Hide file tree
Showing 2 changed files with 910 additions and 589 deletions.
172 changes: 159 additions & 13 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMA-262
text: Set; url: sec-set-o-p-v-throw
text: IsConstructor; url: sec-isconstructor
text: Construct; url: sec-construct
text: own property; url: sec-own-property
text: enumerable; url: sec-property-attributes
text: DefinePropertyOrThrow; url: sec-definepropertyorthrow
url: sec-code-realms
text: Realm
Expand All @@ -120,6 +122,7 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMA-262
text: ECMA-262 section 9.1.8; url: sec-ordinary-object-internal-methods-and-internal-slots-get-p-receiver
text: ECMA-262 section 19.2.2.3; url: sec-function-@@create
text: ECMA-262 section 19.2.3.8; url: sec-function.prototype-@@hasinstance
text: List; url: sec-list-and-record-specification-type
text: Array methods; url: sec-properties-of-the-array-prototype-object
text: typed arrays; url: sec-typedarray-objects
text: GetMethod; url: sec-getmethod
Expand Down Expand Up @@ -1358,8 +1361,10 @@ The type of the attribute, after resolving typedefs, must not be a

* a [=sequence type=]
* a [=dictionary type=]
* a [=record type=]
* a [=union type=]
that has a nullable or non-nullable sequence type or dictionary
that has a nullable or non-nullable sequence type, dictionary,
or record
as one of its [=flattened member types=]

The attribute is <dfn id="dfn-read-only" export>read only</dfn> if the
Expand Down Expand Up @@ -1750,15 +1755,15 @@ corresponding argument omitted.
conversion of <emu-val>undefined</emu-val> to be used (i.e., <emu-val>false</emu-val>).
</p>

If the type of an argument is a [=dictionary type=]
If the type of an argument is a [=dictionary type=] or [=record type=]
or a [=union type=] that has a
dictionary type as one of its [=flattened member types=],
dictionary or record type as one of its [=flattened member types=],
and that dictionary type and its ancestors have no [=required dictionary member|required members=],
and the argument is either the final argument or is followed only by
[=optional arguments=], then
the argument must be specified as optional.
Such arguments are always considered to have a
[=optional argument/default value=] of an empty dictionary,
[=optional argument/default value=] of an empty dictionary or record, as appropriate,
unless otherwise specified.

<div class="note">
Expand Down Expand Up @@ -3249,7 +3254,6 @@ extended attribute’s [=takes a named argument list|named argument list=].

Two types are <dfn id="dfn-distinguishable" export>distinguishable</dfn> if
at most one of the two [=includes a nullable type=]
or is a [=dictionary type=],
and at least one of the following three conditions is true:

1. The two types (taking their [=inner types=]
Expand Down Expand Up @@ -3280,7 +3284,7 @@ and at least one of the following three conditions is true:
<span>callback function</span>
</div></th>
<th><div>
<span>dictionary</span>
<span>dictionary/record</span>
</div></th>
<th><div>
<span>sequence&lt;|T|&gt;</span>
Expand Down Expand Up @@ -3389,7 +3393,7 @@ and at least one of the following three conditions is true:
<td>●</td>
</tr>
<tr>
<th>dictionary</th>
<th>dictionary/record</th>
<td class="belowdiagonal"></td>
<td class="belowdiagonal"></td>
<td class="belowdiagonal"></td>
Expand Down Expand Up @@ -5160,9 +5164,7 @@ type.
NonAnyType :
PrimitiveType Null
PromiseType Null
"ByteString" Null
"DOMString" Null
"USVString" Null
StringType Null
identifier Null
"sequence" "&lt;" Type "&gt;" Null
"object" Null
Expand All @@ -5171,6 +5173,7 @@ type.
"DOMException" Null
BufferRelatedType Null
"FrozenArray" "&lt;" Type "&gt;" Null
RecordType Null
</pre>

<div data-fill-with="grammar-ConstType"></div>
Expand Down Expand Up @@ -5214,11 +5217,23 @@ type.
ε
</pre>

<pre class="grammar" id="prod-StringType">
StringType :
"ByteString"
"DOMString"
"USVString"
</pre>

<pre class="grammar" id="prod-PromiseType">
PromiseType :
"Promise" "&lt;" ReturnType "&gt;"
</pre>

<pre class="grammar" id="prod-RecordType">
RecordType :
"record" "&lt;" StringType "," Type "&gt;"
</pre>

<pre class="grammar" id="prod-Null">
Null :
"?"
Expand Down Expand Up @@ -5664,10 +5679,11 @@ character after an existing type. The inner type must not
be {{any}},
another nullable type, or a [=union type=]
that itself has [=includes a nullable type=]
or has a dictionary type as one of its
or has a dictionary or record type as one of its
[=flattened member types=].

Note: Although dictionary types can in general be nullable, they cannot when used
Note: Although dictionary and record types can in general be nullable,
they cannot when used
as the type of an operation argument or a dictionary member.

Nullable type constant values in IDL are represented in the same way that
Expand Down Expand Up @@ -5737,6 +5753,36 @@ is the concatenation of the type name for |T| and
the string “Sequence”.


<h4 id="idl-record" dictionary lt="record">Record types — record&lt;|K|, |V|&gt;</h4>

A <dfn export>record type</dfn> is a parameterized type
whose values are ordered associative arrays mapping instances of |K| to
instances of |V|. The (key, value) pairs are called
<dfn for="record">mappings</dfn>.
The order of a record's mappings is determined when the record value is created.
In a specification, a record's value can be written:
<blockquote>
« (key1, value1), (key2, value2), … »
</blockquote>

However, there is no way to represent a constant record value in IDL.

|K| must be one of {{DOMString}}, {{USVString}}, or {{ByteString}}.

Records are always passed by value. In language bindings where a record
is represented by an object of some kind, passing a record
to a [=platform object=] will not result in a reference to the record
being kept by that object. Similarly, any record returned from a
platform object will be a copy and modifications made to it will not be visible
to the platform object.

Records must not be used as the type of an [=attribute=] or
[=constant=].

The [=type name=] of a record type is the concatenation of the type
name for |K|, the type name for |V| and the string “Record”.


<h4 oldids="dom-promise" id="idl-promise" interface lt="Promise|Promise&lt;T&gt;">Promise types — Promise&lt;|T|&gt;</h4>

A <dfn id="dfn-promise-type" export>promise type</dfn> is a parameterized type
Expand Down Expand Up @@ -5833,7 +5879,7 @@ be used as a [=member types|union member type=].
The [=number of nullable member types=]
of a [=union type=] must
be 0 or 1, and if it is 1 then the union type must also not have
a [=dictionary type=] in its
a [=dictionary type=] or [=record type=] in its
[=flattened member types=].

A type <dfn id="dfn-includes-a-nullable-type" export>includes a nullable type</dfn> if:
Expand Down Expand Up @@ -7529,6 +7575,101 @@ iterable |iterable| and an iterator getter
</div>


<h4 id="es-record">Records — record&lt;|K|, |V|&gt;</h4>

IDL {{record}}&lt;|K|, |V|&gt; values are represented by
ECMAScript <emu-val>Object</emu-val> values.

<p id="es-to-record">
An ECMAScript value |O| is [=converted to an IDL value|converted=] to an IDL <code>{{record}}&lt;|K|, |V|></code> value as follows:
</p>

<ol class="algorithm">
1. Let |result| be a new empty instance of <code>{{record}}&lt;|K|, |V|></code>.
1. If [=Type=](|O|) is Undefined or Null,
return |result|.
1. If [=Type=](|O|) is not Object,
<a lt="es throw">throw a <emu-val>TypeError</emu-val></a>.
1. Let |keys| be [=?=] |O|.\[[OwnPropertyKeys]]().
1. Repeat, for each element |key| of |keys| in [=List=] order:
1. Let |desc| be [=?=] |O|.\[[GetOwnProperty]](|key|).
1. If |desc| is not <emu-val>undefined</emu-val>
and |desc|.\[[Enumerable]] is <emu-val>true</emu-val>:
1. Let |typedKey| be |key| [=converted to an IDL value=] of type |K|.
1. Let |value| be [=?=] [=Get=](|O|, |key|).
1. Let |typedValue| be |value| [=converted to an IDL value=] of type |V|.
1. If |typedKey| is already a key in |result|, set its value to |typedValue|.

Note: This can happen when |O| is a proxy object.
1. Otherwise, append to |result| a [=record/mapping=] (|typedKey|, |typedValue|).
1. Return |result|.
</ol>

<p id="record-to-es">
An IDL <code>{{record}}&lt;…></code> value |D| is [=converted to an
ECMAScript value|converted=] to an ECMAScript value as follows:
</p>

<ol class="algorithm">
1. Let |result| be [=!=] [=ObjectCreate=]([=%ObjectPrototype%=]).
1. Repeat, for each [=record/mapping=] (|key|, |value|) in |D|:
1. Let |esKey| be |key| [=converted to an ECMAScript value=].
1. Let |esValue| be |value| [=converted to an ECMAScript value=].
1. Let |created| be [=!=] [=CreateDataProperty=](|result|, |esKey|, |esValue|).
1. Assert: |created| is <emu-val>true</emu-val>.
1. Return |result|.
</ol>

<div class="example" id="example-es-record">
Passing the ECMAScript value <code>{b: 3, a: 4}</code> as a
<code>{{record}}&lt;DOMString, double></code> argument
would result in the IDL value « ("b", 3), ("a", 4) ».

Records only consider [=own property|own=] [=enumerable=]
properties, so given an IDL operation
<code>record&lt;DOMString, double>
identity(record&lt;DOMString, double> arg)</code> which returns its
argument, the following code passes its assertions:

<pre highlight="js">
let proto = {a: 3, b: 4};
let obj = {__proto__: proto, d: 5, c: 6}
Object.defineProperty(obj, "e", {value: 7, enumerable: false});
let result = identity(obj);
console.assert(result.a === undefined);
console.assert(result.b === undefined);
console.assert(result.e === undefined);
let entries = Object.entries(result);
console.assert(entries[0][0] === "d");
console.assert(entries[0][1] === 5);
console.assert(entries[1][0] === "c");
console.assert(entries[1][1] === 6);
</pre>

Record keys and values can be constrained, although keys can only be
constrained among the three string types.
The following conversions have the described results:
<table class="data">
<thead><th>Value</th><th>Passed to type</th><th>Result</th></thead>
<tr>
<td><code>{"😞": 1}</code></td>
<td><code>{{record}}&lt;ByteString, double></code></td>
<td><emu-val>TypeError</emu-val></td>
</tr>
<tr>
<td><code>{"\uD83D": 1}</code></td>
<td><code>{{record}}&lt;USVString, double></code></td>
<td>« ("\uFFFD", 1) »</td>
</tr>
<tr>
<td><code>{"\uD83D": {hello: "world"}}</code></td>
<td><code>{{record}}&lt;DOMString, double></code></td>
<td>« ("\uD83D", 0) »</td>
</tr>
</table>
</div>


<h4 id="es-promise">Promise types — Promise&lt;|T|&gt;</h4>

IDL [=promise type=] values are
Expand Down Expand Up @@ -7695,6 +7836,9 @@ represented by ECMAScript values that correspond to the union’s
1. If |types| includes a [=dictionary type=], then return the
result of [=converted to an IDL value|converting=]
|V| to that dictionary type.
1. If |types| includes a [=record type=], then return the
result of [=converted to an IDL value|converting=]
|V| to that record type.
1. If |types| includes a [=callback interface=]
type, then return the result of
[=converted to an IDL value|converting=]
Expand Down Expand Up @@ -9843,6 +9987,7 @@ and a list of IDL values or the special value “missing”. The algorithm beha
and there is an entry in |S| that has one of the following types at position |i| of its type list,
* a [=nullable type=]
* a [=dictionary type=]
* a [=record type=]
* a [=union type=] that
[=includes a nullable type=] or that
has a [=dictionary type=] in its [=flattened member types|flattened members=]
Expand Down Expand Up @@ -9955,6 +10100,7 @@ and a list of IDL values or the special value “missing”. The algorithm beha
there is an entry in |S| that has one of the following types at position |i| of its type list,
* a [=callback interface=] type
* a [=dictionary type=]
* a [=record type=]
* {{object}}
* a [=nullable type|nullable=] version of any of the above types
* a [=union type=] or [=nullable type|nullable=] union type
Expand Down

0 comments on commit 1814384

Please sign in to comment.