*.empty Idea

classic Classic list List threaded Threaded
24 messages Options
12
Reply | Threaded
Open this post in threaded view
|

*.empty Idea

Isiah Meadows-2
I really liked Jordan Harband's suggestion of adding Array.empty, Function.empty, etc. to ES7. It is relatively easy to polyfill as well.

```js
[Array,
 ArrayBuffer,
 Int8Array,
 Int16Array,
 Int32Array,
 Uint8Array,
 Uint8ClampedArray,
 Uint16Array,
 Uint32Array,
 Float32Array,
 Float64Array]
.map(T => [T, new T(0)])
.concat([
  [Object, {}],
  [String, ''],
  [RegExp, /(?:)/],
  [Function, function () {}],
  [GeneratorFunction, function* () {}]
])
.forEach(([root, empty]) =>
  Object.defineProperty(root, 'empty', {
    value: Object.freeze(empty),
    configurable: true,
    enumerable: false,
    writable: false
  }));
```

The code effectively explains what I think would make suitable replacements for each. I don't see the use cases for some of these, though, such as `String.empty` or `RegExp.empty`. 

--
Isiah Meadows

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: *.empty Idea

Jordan Harband
I'd love to bring a proposal to the committee for this since it seems like there's interest.

I suspect that even though some of the "empties" seem useless to some, somebody somewhere will find a use case, and consistency is useful (that everything that could have a concept of "empty" would have a .empty)

Errata:
 - I don't believe `GeneratorFunction` is a global, so we wouldn't need to specify one of those
 - I wonder if `Promise.empty` as `new Promise()`, ie, a forever pending promise, would make sense?
 - or `Date.empty` as `new Date(0)`?
 - We'd definitely want `Map.empty` and `Set.empty` assuming `Object.freeze` actually froze them
 - We'd probably want `Object.freeze(Object.seal(Object.preventExtensions(empty)))`, to be extra restrictive.

Does anyone see any problems or have any objections, beyond "I don't think there's a use case"?

On Sun, Feb 22, 2015 at 2:58 PM, Isiah Meadows <[hidden email]> wrote:
I really liked Jordan Harband's suggestion of adding Array.empty, Function.empty, etc. to ES7. It is relatively easy to polyfill as well.

```js
[Array,
 ArrayBuffer,
 Int8Array,
 Int16Array,
 Int32Array,
 Uint8Array,
 Uint8ClampedArray,
 Uint16Array,
 Uint32Array,
 Float32Array,
 Float64Array]
.map(T => [T, new T(0)])
.concat([
  [Object, {}],
  [String, ''],
  [RegExp, /(?:)/],
  [Function, function () {}],
  [GeneratorFunction, function* () {}]
])
.forEach(([root, empty]) =>
  Object.defineProperty(root, 'empty', {
    value: Object.freeze(empty),
    configurable: true,
    enumerable: false,
    writable: false
  }));
```

The code effectively explains what I think would make suitable replacements for each. I don't see the use cases for some of these, though, such as `String.empty` or `RegExp.empty`. 

--
Isiah Meadows

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: *.empty Idea

Andrea Giammarchi-2
quick one to whoever will write the proposal: please bear in mind the empty function **must** have a frozen prototype too

Regards

On Sun, Feb 22, 2015 at 11:18 PM, Jordan Harband <[hidden email]> wrote:
I'd love to bring a proposal to the committee for this since it seems like there's interest.

I suspect that even though some of the "empties" seem useless to some, somebody somewhere will find a use case, and consistency is useful (that everything that could have a concept of "empty" would have a .empty)

Errata:
 - I don't believe `GeneratorFunction` is a global, so we wouldn't need to specify one of those
 - I wonder if `Promise.empty` as `new Promise()`, ie, a forever pending promise, would make sense?
 - or `Date.empty` as `new Date(0)`?
 - We'd definitely want `Map.empty` and `Set.empty` assuming `Object.freeze` actually froze them
 - We'd probably want `Object.freeze(Object.seal(Object.preventExtensions(empty)))`, to be extra restrictive.

Does anyone see any problems or have any objections, beyond "I don't think there's a use case"?

On Sun, Feb 22, 2015 at 2:58 PM, Isiah Meadows <[hidden email]> wrote:
I really liked Jordan Harband's suggestion of adding Array.empty, Function.empty, etc. to ES7. It is relatively easy to polyfill as well.

```js
[Array,
 ArrayBuffer,
 Int8Array,
 Int16Array,
 Int32Array,
 Uint8Array,
 Uint8ClampedArray,
 Uint16Array,
 Uint32Array,
 Float32Array,
 Float64Array]
.map(T => [T, new T(0)])
.concat([
  [Object, {}],
  [String, ''],
  [RegExp, /(?:)/],
  [Function, function () {}],
  [GeneratorFunction, function* () {}]
])
.forEach(([root, empty]) =>
  Object.defineProperty(root, 'empty', {
    value: Object.freeze(empty),
    configurable: true,
    enumerable: false,
    writable: false
  }));
```

The code effectively explains what I think would make suitable replacements for each. I don't see the use cases for some of these, though, such as `String.empty` or `RegExp.empty`. 

--
Isiah Meadows

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: *.empty Idea

Isiah Meadows-2


On Feb 23, 2015 6:06 AM, "Andrea Giammarchi" <[hidden email]> wrote:
>
> quick one to whoever will write the proposal: please bear in mind the empty function **must** have a frozen prototype too
>
> Regards

Andrea, good catch.

>
> On Sun, Feb 22, 2015 at 11:18 PM, Jordan Harband <[hidden email]> wrote:
>>
>> I'd love to bring a proposal to the committee for this since it seems like there's interest.
>>
>> I suspect that even though some of the "empties" seem useless to some, somebody somewhere will find a use case, and consistency is useful (that everything that could have a concept of "empty" would have a .empty)
>>
>> Errata:
>>  - I don't believe `GeneratorFunction` is a global, so we wouldn't need to specify one of those

I actually forgot about that... Makes no sense to me why there isn't one in the first place. Maybe an oversight in ES6? (could probably be put on track for ES7 easily, simply requiring that the string argument represents the source code for a GeneratorBody). Probably better suited to a separate proposal, though. I can write a more accurate prollyfill later today.

>>  - I wonder if `Promise.empty` as `new Promise()`, ie, a forever pending promise, would make sense?

Maybe a forever-fulfilled one? Although there are probably use cases for all three kinds, pending, fulfilled, and rejected. Maybe all three would be better than a simple 'empty' one.

>>  - or `Date.empty` as `new Date(0)`?

That could work.

>>  - We'd definitely want `Map.empty` and `Set.empty` assuming `Object.freeze` actually froze them

Object.freeze does not freeze them, as far as I know. It might require method overrides.

>>  - We'd probably want `Object.freeze(Object.seal(Object.preventExtensions(empty)))`, to be extra restrictive.

Doesn't Object.freeze imply the other two? I thought it did.

>>
>> Does anyone see any problems or have any objections, beyond "I don't think there's a use case"?
>>
>> On Sun, Feb 22, 2015 at 2:58 PM, Isiah Meadows <[hidden email]> wrote:
>>>
>>> I really liked Jordan Harband's suggestion of adding Array.empty, Function.empty, etc. to ES7. It is relatively easy to polyfill as well.
>>>
>>> ```js
>>> [Array,
>>>  ArrayBuffer,
>>>  Int8Array,
>>>  Int16Array,
>>>  Int32Array,
>>>  Uint8Array,
>>>  Uint8ClampedArray,
>>>  Uint16Array,
>>>  Uint32Array,
>>>  Float32Array,
>>>  Float64Array]
>>> .map(T => [T, new T(0)])
>>> .concat([
>>>   [Object, {}],
>>>   [String, ''],
>>>   [RegExp, /(?:)/],
>>>   [Function, function () {}],
>>>   [GeneratorFunction, function* () {}]
>>> ])
>>> .forEach(([root, empty]) =>
>>>   Object.defineProperty(root, 'empty', {
>>>     value: Object.freeze(empty),
>>>     configurable: true,
>>>     enumerable: false,
>>>     writable: false
>>>   }));
>>> ```
>>>
>>> The code effectively explains what I think would make suitable replacements for each. I don't see the use cases for some of these, though, such as `String.empty` or `RegExp.empty`. 
>>>
>>> --
>>> Isiah Meadows
>>>
>>> _______________________________________________
>>> es-discuss mailing list
>>> [hidden email]
>>> https://mail.mozilla.org/listinfo/es-discuss
>>>
>>
>>
>> _______________________________________________
>> es-discuss mailing list
>> [hidden email]
>> https://mail.mozilla.org/listinfo/es-discuss
>>
>


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: *.empty Idea

Mark S. Miller-2


On Mon, Feb 23, 2015 at 11:59 AM, Isiah Meadows <[hidden email]> wrote:

On Feb 23, 2015 6:06 AM, "Andrea Giammarchi" <[hidden email]> wrote:

> On Sun, Feb 22, 2015 at 11:18 PM, Jordan Harband <[hidden email]> wrote:

[...] 

>>  - We'd definitely want `Map.empty` and `Set.empty` assuming `Object.freeze` actually froze them

Object.freeze does not freeze them, as far as I know. It might require method overrides.

Object.freeze does not freeze their state. A proposal for a way to either freeze the state of collections, and/or to create frozen snapshots of collections, for future ES would be welcome and appreciated. I encourage any such effort to pay attention to Clojure and React.

 

>>  - We'd probably want `Object.freeze(Object.seal(Object.preventExtensions(empty)))`, to be extra restrictive.

Doesn't Object.freeze imply the other two? I thought it did.


It does. Given that all these methods of Object have their original value and that x is not a proxy

    Object.freeze(Object.seal(Object.preventExtensions(x)))

must be equivalent to

    Object.freeze(x)


--
    Cheers,
    --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: *.empty Idea

Isiah Meadows-2


On Feb 23, 2015 3:31 PM, "Mark S. Miller" <[hidden email]> wrote:
>
>
>
> On Mon, Feb 23, 2015 at 11:59 AM, Isiah Meadows <[hidden email]> wrote:
>>
>> On Feb 23, 2015 6:06 AM, "Andrea Giammarchi" <[hidden email]> wrote:
>>
>> > On Sun, Feb 22, 2015 at 11:18 PM, Jordan Harband <[hidden email]> wrote:
>
> [...] 
>>
>> >>  - We'd definitely want `Map.empty` and `Set.empty` assuming `Object.freeze` actually froze them
>>
>> Object.freeze does not freeze them, as far as I know. It might require method overrides.
>
> Object.freeze does not freeze their state. A proposal for a way to either freeze the state of collections, and/or to create frozen snapshots of collections, for future ES would be welcome and appreciated. I encourage any such effort to pay attention to Clojure and React.
>
>  
>>
>> >>  - We'd probably want `Object.freeze(Object.seal(Object.preventExtensions(empty)))`, to be extra restrictive.
>>
>> Doesn't Object.freeze imply the other two? I thought it did.
>
>
> It does. Given that all these methods of Object have their original value and that x is not a proxy
>
>     Object.freeze(Object.seal(Object.preventExtensions(x)))
>
> must be equivalent to
>
>     Object.freeze(x)
>

Pardon my ignorance, but in what cases does the proxy in this case differ? (although it's not entirely relevant in this particular case)

>
> --
>     Cheers,
>     --MarkM


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: *.empty Idea

Mark S. Miller-2
Only that the proxy can detect each of the operations as a distinct trap, and do something weird. A proxy that intend to emulate anything like a normal object would choose not to, preserving by convention this equivalence. It becomes a matter of informal unchecked contract conformance, rather than a platform guarantee.



On Mon, Feb 23, 2015 at 4:28 PM, Isiah Meadows <[hidden email]> wrote:


On Feb 23, 2015 3:31 PM, "Mark S. Miller" <[hidden email]> wrote:
>
>
>
> On Mon, Feb 23, 2015 at 11:59 AM, Isiah Meadows <[hidden email]> wrote:
>>
>> On Feb 23, 2015 6:06 AM, "Andrea Giammarchi" <[hidden email]> wrote:
>>
>> > On Sun, Feb 22, 2015 at 11:18 PM, Jordan Harband <[hidden email]> wrote:
>
> [...] 
>>
>> >>  - We'd definitely want `Map.empty` and `Set.empty` assuming `Object.freeze` actually froze them
>>
>> Object.freeze does not freeze them, as far as I know. It might require method overrides.
>
> Object.freeze does not freeze their state. A proposal for a way to either freeze the state of collections, and/or to create frozen snapshots of collections, for future ES would be welcome and appreciated. I encourage any such effort to pay attention to Clojure and React.
>
>  
>>
>> >>  - We'd probably want `Object.freeze(Object.seal(Object.preventExtensions(empty)))`, to be extra restrictive.
>>
>> Doesn't Object.freeze imply the other two? I thought it did.
>
>
> It does. Given that all these methods of Object have their original value and that x is not a proxy
>
>     Object.freeze(Object.seal(Object.preventExtensions(x)))
>
> must be equivalent to
>
>     Object.freeze(x)
>

Pardon my ignorance, but in what cases does the proxy in this case differ? (although it's not entirely relevant in this particular case)

>
> --
>     Cheers,
>     --MarkM




--
    Cheers,
    --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: *.empty Idea

C. Scott Ananian
In reply to this post by Mark S. Miller-2
On Mon, Feb 23, 2015 at 3:31 PM, Mark S. Miller <[hidden email]> wrote:
On Mon, Feb 23, 2015 at 11:59 AM, Isiah Meadows <[hidden email]> wrote:

On Feb 23, 2015 6:06 AM, "Andrea Giammarchi" <[hidden email]> wrote:

> On Sun, Feb 22, 2015 at 11:18 PM, Jordan Harband <[hidden email]> wrote:

[...] 

>>  - We'd definitely want `Map.empty` and `Set.empty` assuming `Object.freeze` actually froze them

Object.freeze does not freeze them, as far as I know. It might require method overrides.

Object.freeze does not freeze their state. A proposal for a way to either freeze the state of collections, and/or to create frozen snapshots of collections, for future ES would be welcome and appreciated. I encourage any such effort to pay attention to Clojure and React.

I ran into this today.

As a strawman proposal:

> Add "If TestIntegrityLevel(M, "frozen") is true, throw a TypeError exception" between steps 3 and 4 of 23.1.3.1 (Map.prototype.clear), 23.1.3.3 (Map.prototype.delete), 23.1.3.9 (Map.prototype.set), 23.2.3.1 (Set.prototype.add), 23.2.3.2 (Set.prototype.clear), and 23.2.3.4 (Set.prototype.delete).

This wouldn't be some fancy all-singing all-dancing collection snapshot, and would still leave the user responsible for freezing the prototype, etc, but it would bring Map and Set back into parity with object (that is, m.get(f) behaves for the most part like o[f]).

Users would still have to special-case Map/Set when they implement their own deepFreeze() methods, etc, but this ensures that the internal list is actually protected.  It is (AFAICT) otherwise impossible in ES6 to maintain object identity when "freezing" an collection.
 --scott


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: *.empty Idea

Jordan Harband
I really like this - I'm writing up a ".empty" proposal and I'll include this as part of it, thanks!

On Thu, Apr 30, 2015 at 9:52 AM, C. Scott Ananian <[hidden email]> wrote:
On Mon, Feb 23, 2015 at 3:31 PM, Mark S. Miller <[hidden email]> wrote:
On Mon, Feb 23, 2015 at 11:59 AM, Isiah Meadows <[hidden email]> wrote:

On Feb 23, 2015 6:06 AM, "Andrea Giammarchi" <[hidden email]> wrote:

> On Sun, Feb 22, 2015 at 11:18 PM, Jordan Harband <[hidden email]> wrote:

[...] 

>>  - We'd definitely want `Map.empty` and `Set.empty` assuming `Object.freeze` actually froze them

Object.freeze does not freeze them, as far as I know. It might require method overrides.

Object.freeze does not freeze their state. A proposal for a way to either freeze the state of collections, and/or to create frozen snapshots of collections, for future ES would be welcome and appreciated. I encourage any such effort to pay attention to Clojure and React.

I ran into this today.

As a strawman proposal:

> Add "If TestIntegrityLevel(M, "frozen") is true, throw a TypeError exception" between steps 3 and 4 of 23.1.3.1 (Map.prototype.clear), 23.1.3.3 (Map.prototype.delete), 23.1.3.9 (Map.prototype.set), 23.2.3.1 (Set.prototype.add), 23.2.3.2 (Set.prototype.clear), and 23.2.3.4 (Set.prototype.delete).

This wouldn't be some fancy all-singing all-dancing collection snapshot, and would still leave the user responsible for freezing the prototype, etc, but it would bring Map and Set back into parity with object (that is, m.get(f) behaves for the most part like o[f]).

Users would still have to special-case Map/Set when they implement their own deepFreeze() methods, etc, but this ensures that the internal list is actually protected.  It is (AFAICT) otherwise impossible in ES6 to maintain object identity when "freezing" an collection.
 --scott


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: *.empty Idea

Mark S. Miller-2
In reply to this post by C. Scott Ananian
This must *not* be hung off of Object.freeze. Object.freeze is about tamper proofing an object's API, not about making its internal state immutable. I regret the term "freeze" for this purpose as it repeatedly suggests this confusion. OTOH, because of the override mistake, Object.freeze is not directly usable as a good tamper proofing operation, so in this sense it was fortuitously good that it did not use up the name tamperProof.

Deep immutability is a crucial concept deserving of good support for many reasons including security patterns. Deep immutability must of course include encapsulated state captured by lexical closures, and it must do so without violating the security properties that this very encapsulation guarantees. The Auditors of E <http://www.erights.org/elang/kernel/auditors/>, <http://wiki.erights.org/wiki/Guard-based_auditing> and Joe-E <http://www.cs.berkeley.edu/~daw/papers/pure-ccs08.pdf> <http://www.eecs.berkeley.edu/Pubs/TechRpts/2012/EECS-2012-244.html> provided solutions to this dilemma in their respective languages. E and Joe-E also support shallower forms of immutability that are specific to collections -- that are distinct from API tamper proofing but that do not extend to considering the mutability of the contents of the collections.

I welcome proposals that would make sense for JavaScript.



On Thu, Apr 30, 2015 at 9:52 AM, C. Scott Ananian <[hidden email]> wrote:
On Mon, Feb 23, 2015 at 3:31 PM, Mark S. Miller <[hidden email]> wrote:
On Mon, Feb 23, 2015 at 11:59 AM, Isiah Meadows <[hidden email]> wrote:

On Feb 23, 2015 6:06 AM, "Andrea Giammarchi" <[hidden email]> wrote:

> On Sun, Feb 22, 2015 at 11:18 PM, Jordan Harband <[hidden email]> wrote:

[...] 

>>  - We'd definitely want `Map.empty` and `Set.empty` assuming `Object.freeze` actually froze them

Object.freeze does not freeze them, as far as I know. It might require method overrides.

Object.freeze does not freeze their state. A proposal for a way to either freeze the state of collections, and/or to create frozen snapshots of collections, for future ES would be welcome and appreciated. I encourage any such effort to pay attention to Clojure and React.

I ran into this today.

As a strawman proposal:

> Add "If TestIntegrityLevel(M, "frozen") is true, throw a TypeError exception" between steps 3 and 4 of 23.1.3.1 (Map.prototype.clear), 23.1.3.3 (Map.prototype.delete), 23.1.3.9 (Map.prototype.set), 23.2.3.1 (Set.prototype.add), 23.2.3.2 (Set.prototype.clear), and 23.2.3.4 (Set.prototype.delete).

This wouldn't be some fancy all-singing all-dancing collection snapshot, and would still leave the user responsible for freezing the prototype, etc, but it would bring Map and Set back into parity with object (that is, m.get(f) behaves for the most part like o[f]).

Users would still have to special-case Map/Set when they implement their own deepFreeze() methods, etc, but this ensures that the internal list is actually protected.  It is (AFAICT) otherwise impossible in ES6 to maintain object identity when "freezing" an collection.
 --scott




--
    Cheers,
    --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: *.empty Idea

C. Scott Ananian
Mark: I also agree that `Object.freeze` is flawed, and I welcome a proper proposal for `Object.tamperProof` or what have you.  But `Object.freeze` works just well enough in the short term that people can build useful mechanisms on top of it.

My proposal just makes `Map`/`Set` behave consistently with `Object` with respect to `Object.freeze` (preserving the consistency between object fields and the behavior of `Map`).  I think that consistency is preferable to the current situation, even though (as I said) I welcome a proper mechanism for immutability in the future.

Said a different way: one day we will have `Object.tamperProof` and it will be wonderful.  But we will always be stuck with `Object.freeze` as well, because it's been released into the while.  Let's at least try to make `Object.freeze` a little more consistent, and not let future features prevent us from improving what we have now.
  --scott


On Thu, Apr 30, 2015 at 1:17 PM, Mark S. Miller <[hidden email]> wrote:
This must *not* be hung off of Object.freeze. Object.freeze is about tamper proofing an object's API, not about making its internal state immutable. I regret the term "freeze" for this purpose as it repeatedly suggests this confusion. OTOH, because of the override mistake, Object.freeze is not directly usable as a good tamper proofing operation, so in this sense it was fortuitously good that it did not use up the name tamperProof.

Deep immutability is a crucial concept deserving of good support for many reasons including security patterns. Deep immutability must of course include encapsulated state captured by lexical closures, and it must do so without violating the security properties that this very encapsulation guarantees. The Auditors of E <http://www.erights.org/elang/kernel/auditors/>, <http://wiki.erights.org/wiki/Guard-based_auditing> and Joe-E <http://www.cs.berkeley.edu/~daw/papers/pure-ccs08.pdf> <http://www.eecs.berkeley.edu/Pubs/TechRpts/2012/EECS-2012-244.html> provided solutions to this dilemma in their respective languages. E and Joe-E also support shallower forms of immutability that are specific to collections -- that are distinct from API tamper proofing but that do not extend to considering the mutability of the contents of the collections.

I welcome proposals that would make sense for JavaScript.



On Thu, Apr 30, 2015 at 9:52 AM, C. Scott Ananian <[hidden email]> wrote:
On Mon, Feb 23, 2015 at 3:31 PM, Mark S. Miller <[hidden email]> wrote:
On Mon, Feb 23, 2015 at 11:59 AM, Isiah Meadows <[hidden email]> wrote:

On Feb 23, 2015 6:06 AM, "Andrea Giammarchi" <[hidden email]> wrote:

> On Sun, Feb 22, 2015 at 11:18 PM, Jordan Harband <[hidden email]> wrote:

[...] 

>>  - We'd definitely want `Map.empty` and `Set.empty` assuming `Object.freeze` actually froze them

Object.freeze does not freeze them, as far as I know. It might require method overrides.

Object.freeze does not freeze their state. A proposal for a way to either freeze the state of collections, and/or to create frozen snapshots of collections, for future ES would be welcome and appreciated. I encourage any such effort to pay attention to Clojure and React.

I ran into this today.

As a strawman proposal:

> Add "If TestIntegrityLevel(M, "frozen") is true, throw a TypeError exception" between steps 3 and 4 of 23.1.3.1 (Map.prototype.clear), 23.1.3.3 (Map.prototype.delete), 23.1.3.9 (Map.prototype.set), 23.2.3.1 (Set.prototype.add), 23.2.3.2 (Set.prototype.clear), and 23.2.3.4 (Set.prototype.delete).

This wouldn't be some fancy all-singing all-dancing collection snapshot, and would still leave the user responsible for freezing the prototype, etc, but it would bring Map and Set back into parity with object (that is, m.get(f) behaves for the most part like o[f]).

Users would still have to special-case Map/Set when they implement their own deepFreeze() methods, etc, but this ensures that the internal list is actually protected.  It is (AFAICT) otherwise impossible in ES6 to maintain object identity when "freezing" an collection.
 --scott




--
    Cheers,
    --MarkM


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: *.empty Idea

Mark S. Miller-2
Hi Scott, this would only be confusing. Object.tamperProof is built on and implies Object.freeze. It is like Object.freeze except that it replaces (some :( ) data properties with accessors in order to work around the override mistake.

Object.freeze only operates on properties and the [[Extensible]] bit, nothing more. This is by design. It is the wrong tool for the (very valuable!) job you seek.

Again, my apologies for the terrible name.



On Thu, Apr 30, 2015 at 11:04 AM, C. Scott Ananian <[hidden email]> wrote:
Mark: I also agree that `Object.freeze` is flawed, and I welcome a proper proposal for `Object.tamperProof` or what have you.  But `Object.freeze` works just well enough in the short term that people can build useful mechanisms on top of it.

My proposal just makes `Map`/`Set` behave consistently with `Object` with respect to `Object.freeze` (preserving the consistency between object fields and the behavior of `Map`).  I think that consistency is preferable to the current situation, even though (as I said) I welcome a proper mechanism for immutability in the future.

Said a different way: one day we will have `Object.tamperProof` and it will be wonderful.  But we will always be stuck with `Object.freeze` as well, because it's been released into the while.  Let's at least try to make `Object.freeze` a little more consistent, and not let future features prevent us from improving what we have now.
  --scott


On Thu, Apr 30, 2015 at 1:17 PM, Mark S. Miller <[hidden email]> wrote:
This must *not* be hung off of Object.freeze. Object.freeze is about tamper proofing an object's API, not about making its internal state immutable. I regret the term "freeze" for this purpose as it repeatedly suggests this confusion. OTOH, because of the override mistake, Object.freeze is not directly usable as a good tamper proofing operation, so in this sense it was fortuitously good that it did not use up the name tamperProof.

Deep immutability is a crucial concept deserving of good support for many reasons including security patterns. Deep immutability must of course include encapsulated state captured by lexical closures, and it must do so without violating the security properties that this very encapsulation guarantees. The Auditors of E <http://www.erights.org/elang/kernel/auditors/>, <http://wiki.erights.org/wiki/Guard-based_auditing> and Joe-E <http://www.cs.berkeley.edu/~daw/papers/pure-ccs08.pdf> <http://www.eecs.berkeley.edu/Pubs/TechRpts/2012/EECS-2012-244.html> provided solutions to this dilemma in their respective languages. E and Joe-E also support shallower forms of immutability that are specific to collections -- that are distinct from API tamper proofing but that do not extend to considering the mutability of the contents of the collections.

I welcome proposals that would make sense for JavaScript.



On Thu, Apr 30, 2015 at 9:52 AM, C. Scott Ananian <[hidden email]> wrote:
On Mon, Feb 23, 2015 at 3:31 PM, Mark S. Miller <[hidden email]> wrote:
On Mon, Feb 23, 2015 at 11:59 AM, Isiah Meadows <[hidden email]> wrote:

On Feb 23, 2015 6:06 AM, "Andrea Giammarchi" <[hidden email]> wrote:

> On Sun, Feb 22, 2015 at 11:18 PM, Jordan Harband <[hidden email]> wrote:

[...] 

>>  - We'd definitely want `Map.empty` and `Set.empty` assuming `Object.freeze` actually froze them

Object.freeze does not freeze them, as far as I know. It might require method overrides.

Object.freeze does not freeze their state. A proposal for a way to either freeze the state of collections, and/or to create frozen snapshots of collections, for future ES would be welcome and appreciated. I encourage any such effort to pay attention to Clojure and React.

I ran into this today.

As a strawman proposal:

> Add "If TestIntegrityLevel(M, "frozen") is true, throw a TypeError exception" between steps 3 and 4 of 23.1.3.1 (Map.prototype.clear), 23.1.3.3 (Map.prototype.delete), 23.1.3.9 (Map.prototype.set), 23.2.3.1 (Set.prototype.add), 23.2.3.2 (Set.prototype.clear), and 23.2.3.4 (Set.prototype.delete).

This wouldn't be some fancy all-singing all-dancing collection snapshot, and would still leave the user responsible for freezing the prototype, etc, but it would bring Map and Set back into parity with object (that is, m.get(f) behaves for the most part like o[f]).

Users would still have to special-case Map/Set when they implement their own deepFreeze() methods, etc, but this ensures that the internal list is actually protected.  It is (AFAICT) otherwise impossible in ES6 to maintain object identity when "freezing" an collection.
 --scott




--
    Cheers,
    --MarkM




--
    Cheers,
    --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: *.empty Idea

Mark S. Miller-2
It would also not be compatible with ES6 code. SES will be freezing Map, Set, WeakMap, and WeakSet instances in order to tamper proof their API. I expect many others will as well. Having this freeze then cause a non-mutability in ES7 will break all such ES6 code. This is a non-starter all around.


On Thu, Apr 30, 2015 at 11:18 AM, Mark S. Miller <[hidden email]> wrote:
Hi Scott, this would only be confusing. Object.tamperProof is built on and implies Object.freeze. It is like Object.freeze except that it replaces (some :( ) data properties with accessors in order to work around the override mistake.

Object.freeze only operates on properties and the [[Extensible]] bit, nothing more. This is by design. It is the wrong tool for the (very valuable!) job you seek.

Again, my apologies for the terrible name.



On Thu, Apr 30, 2015 at 11:04 AM, C. Scott Ananian <[hidden email]> wrote:
Mark: I also agree that `Object.freeze` is flawed, and I welcome a proper proposal for `Object.tamperProof` or what have you.  But `Object.freeze` works just well enough in the short term that people can build useful mechanisms on top of it.

My proposal just makes `Map`/`Set` behave consistently with `Object` with respect to `Object.freeze` (preserving the consistency between object fields and the behavior of `Map`).  I think that consistency is preferable to the current situation, even though (as I said) I welcome a proper mechanism for immutability in the future.

Said a different way: one day we will have `Object.tamperProof` and it will be wonderful.  But we will always be stuck with `Object.freeze` as well, because it's been released into the while.  Let's at least try to make `Object.freeze` a little more consistent, and not let future features prevent us from improving what we have now.
  --scott


On Thu, Apr 30, 2015 at 1:17 PM, Mark S. Miller <[hidden email]> wrote:
This must *not* be hung off of Object.freeze. Object.freeze is about tamper proofing an object's API, not about making its internal state immutable. I regret the term "freeze" for this purpose as it repeatedly suggests this confusion. OTOH, because of the override mistake, Object.freeze is not directly usable as a good tamper proofing operation, so in this sense it was fortuitously good that it did not use up the name tamperProof.

Deep immutability is a crucial concept deserving of good support for many reasons including security patterns. Deep immutability must of course include encapsulated state captured by lexical closures, and it must do so without violating the security properties that this very encapsulation guarantees. The Auditors of E <http://www.erights.org/elang/kernel/auditors/>, <http://wiki.erights.org/wiki/Guard-based_auditing> and Joe-E <http://www.cs.berkeley.edu/~daw/papers/pure-ccs08.pdf> <http://www.eecs.berkeley.edu/Pubs/TechRpts/2012/EECS-2012-244.html> provided solutions to this dilemma in their respective languages. E and Joe-E also support shallower forms of immutability that are specific to collections -- that are distinct from API tamper proofing but that do not extend to considering the mutability of the contents of the collections.

I welcome proposals that would make sense for JavaScript.



On Thu, Apr 30, 2015 at 9:52 AM, C. Scott Ananian <[hidden email]> wrote:
On Mon, Feb 23, 2015 at 3:31 PM, Mark S. Miller <[hidden email]> wrote:
On Mon, Feb 23, 2015 at 11:59 AM, Isiah Meadows <[hidden email]> wrote:

On Feb 23, 2015 6:06 AM, "Andrea Giammarchi" <[hidden email]> wrote:

> On Sun, Feb 22, 2015 at 11:18 PM, Jordan Harband <[hidden email]> wrote:

[...] 

>>  - We'd definitely want `Map.empty` and `Set.empty` assuming `Object.freeze` actually froze them

Object.freeze does not freeze them, as far as I know. It might require method overrides.

Object.freeze does not freeze their state. A proposal for a way to either freeze the state of collections, and/or to create frozen snapshots of collections, for future ES would be welcome and appreciated. I encourage any such effort to pay attention to Clojure and React.

I ran into this today.

As a strawman proposal:

> Add "If TestIntegrityLevel(M, "frozen") is true, throw a TypeError exception" between steps 3 and 4 of 23.1.3.1 (Map.prototype.clear), 23.1.3.3 (Map.prototype.delete), 23.1.3.9 (Map.prototype.set), 23.2.3.1 (Set.prototype.add), 23.2.3.2 (Set.prototype.clear), and 23.2.3.4 (Set.prototype.delete).

This wouldn't be some fancy all-singing all-dancing collection snapshot, and would still leave the user responsible for freezing the prototype, etc, but it would bring Map and Set back into parity with object (that is, m.get(f) behaves for the most part like o[f]).

Users would still have to special-case Map/Set when they implement their own deepFreeze() methods, etc, but this ensures that the internal list is actually protected.  It is (AFAICT) otherwise impossible in ES6 to maintain object identity when "freezing" an collection.
 --scott




--
    Cheers,
    --MarkM




--
    Cheers,
    --MarkM



--
    Cheers,
    --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: *.empty Idea

C. Scott Ananian
On Thu, Apr 30, 2015 at 2:22 PM, Mark S. Miller <[hidden email]> wrote:
It would also not be compatible with ES6 code. SES will be freezing Map, Set, WeakMap, and WeakSet instances in order to tamper proof their API. I expect many others will as well. Having this freeze then cause a non-mutability in ES7 will break all such ES6 code. This is a non-starter all around.

Couldn't SES use Object.seal/Object.preventExtensions/Object.defineProperty to perform tamper-proofing without flipping the "frozen" bit?
 --scott

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: *.empty Idea

Mark S. Miller-2
It doesn't matter. Others will do the same thing in ES6 and then break under your proposal in ES7.


On Thu, Apr 30, 2015 at 11:42 AM, C. Scott Ananian <[hidden email]> wrote:
On Thu, Apr 30, 2015 at 2:22 PM, Mark S. Miller <[hidden email]> wrote:
It would also not be compatible with ES6 code. SES will be freezing Map, Set, WeakMap, and WeakSet instances in order to tamper proof their API. I expect many others will as well. Having this freeze then cause a non-mutability in ES7 will break all such ES6 code. This is a non-starter all around.

Couldn't SES use Object.seal/Object.preventExtensions/Object.defineProperty to perform tamper-proofing without flipping the "frozen" bit?
 --scott



--
    Cheers,
    --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: *.empty Idea

C. Scott Ananian
In reply to this post by C. Scott Ananian
Can you make an alternative proposal that still preserves the essential property of Object.freeze on collections -- that is to say, preserves object identity while preventing future writes?

Here's another strawman:
> Add "[[Immutable]]" to the arguments of OrdinaryCreateFromConstructor in step 2 of 23.1.1.1 (Map) and 23.2.1.1 (Set)
> Add "If the [[Immutable]] internal slot of M is true, throw a TypeError exception" between steps 3 and 4 of 23.1.3.1 (Map.prototype.clear), 23.1.3.3 (Map.prototype.delete), 23.1.3.9 (Map.prototype.set), 23.2.3.1 (Set.prototype.add), 23.2.3.2 (Set.prototype.clear), and 23.2.3.4 (Set.prototype.delete).
> Add `Map.prototype.makeReadOnly()` and `Set.prototype.makeReadOnly()` methods with the definition:
>  1. Let M be the this value.
>  2. If Type(M) is not Object, throw a TypeError exception
>  3. If M does not have a [[Immutable]] internal slot, throw a TypeError exception
>  4. Set the [[Immutable]] internal slot of M to true.

This is somewhat awkward and ad-hoc, but it won't break ES6 code.

I am concerned about this issue in part because as written is seems to be impossible to prevent writes to Map.  If you subclass it, freeze it, override set/delete/etc it is still possible to mutate the map using `Map.set.call(m, 'a', 'b');`.  And there is no way for use code to get at the [[MapData]] slot to protect it.
  --scott


On Thu, Apr 30, 2015 at 2:42 PM, C. Scott Ananian <[hidden email]> wrote:
On Thu, Apr 30, 2015 at 2:22 PM, Mark S. Miller <[hidden email]> wrote:
It would also not be compatible with ES6 code. SES will be freezing Map, Set, WeakMap, and WeakSet instances in order to tamper proof their API. I expect many others will as well. Having this freeze then cause a non-mutability in ES7 will break all such ES6 code. This is a non-starter all around.

Couldn't SES use Object.seal/Object.preventExtensions/Object.defineProperty to perform tamper-proofing without flipping the "frozen" bit?
 --scott


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: *.empty Idea

Domenic Denicola
It's fine to propose something to make maps immutable. Just don't call it Object.freeze.






On Thu, Apr 30, 2015 at 11:56 AM -0700, "C. Scott Ananian" <[hidden email]> wrote:

Can you make an alternative proposal that still preserves the essential property of Object.freeze on collections -- that is to say, preserves object identity while preventing future writes?

Here's another strawman:
> Add "[[Immutable]]" to the arguments of OrdinaryCreateFromConstructor in step 2 of 23.1.1.1 (Map) and 23.2.1.1 (Set)
> Add "If the [[Immutable]] internal slot of M is true, throw a TypeError exception" between steps 3 and 4 of 23.1.3.1 (Map.prototype.clear), 23.1.3.3 (Map.prototype.delete), 23.1.3.9 (Map.prototype.set), 23.2.3.1 (Set.prototype.add), 23.2.3.2 (Set.prototype.clear), and 23.2.3.4 (Set.prototype.delete).
> Add `Map.prototype.makeReadOnly()` and `Set.prototype.makeReadOnly()` methods with the definition:
>  1. Let M be the this value.
>  2. If Type(M) is not Object, throw a TypeError exception
>  3. If M does not have a [[Immutable]] internal slot, throw a TypeError exception
>  4. Set the [[Immutable]] internal slot of M to true.

This is somewhat awkward and ad-hoc, but it won't break ES6 code.

I am concerned about this issue in part because as written is seems to be impossible to prevent writes to Map.  If you subclass it, freeze it, override set/delete/etc it is still possible to mutate the map using `Map.set.call(m, 'a', 'b');`.  And there is no way for use code to get at the [[MapData]] slot to protect it.
  --scott


On Thu, Apr 30, 2015 at 2:42 PM, C. Scott Ananian <[hidden email]> wrote:
On Thu, Apr 30, 2015 at 2:22 PM, Mark S. Miller <[hidden email]> wrote:
It would also not be compatible with ES6 code. SES will be freezing Map, Set, WeakMap, and WeakSet instances in order to tamper proof their API. I expect many others will as well. Having this freeze then cause a non-mutability in ES7 will break all such ES6 code. This is a non-starter all around.

Couldn't SES use Object.seal/Object.preventExtensions/Object.defineProperty to perform tamper-proofing without flipping the "frozen" bit?
 --scott


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: *.empty Idea

Mark S. Miller-2
In reply to this post by C. Scott Ananian
That is indeed the kind of proposal I was looking for, thanks. An issue is that it locks down the Map in place, which is a design issue we can debate but is not necessarily a show stopper. I would be happy to see this enter stage zero to get the conversation started,


Another possibility is to have collections respond to messages like

.snapshot() -- returns an immutable snapshot of the receiver collection
.diverge() -- returns a mutable collection whose initial state is the a snapshot of the receiver
.readOnly() -- returns a readOnly view of a possibly mutable collection.

by returning a new derived collection with the desired mutability. Given that c is a conforming collection, we'd have the following algebraic properties

c.snapshot().snapshot() === c.snapshot()
c.snapshot().readOnly() === c.snapshot()
c.readOnly().readOnly() === c.readOnly()
c.diverge() !== c


Further, for each mutable collection type, it would be nice (by possibly too breaking of a change) to insert a superclass above it whose prototype holds its query method including the three above, leaving only the mutation methods on the existing subtype. Then, .snapshot() and .readOnly() could return an instance of this supertype that is not an instance of the mutable subtype.



On Thu, Apr 30, 2015 at 11:56 AM, C. Scott Ananian <[hidden email]> wrote:
Can you make an alternative proposal that still preserves the essential property of Object.freeze on collections -- that is to say, preserves object identity while preventing future writes?

Here's another strawman:
> Add "[[Immutable]]" to the arguments of OrdinaryCreateFromConstructor in step 2 of 23.1.1.1 (Map) and 23.2.1.1 (Set)
> Add "If the [[Immutable]] internal slot of M is true, throw a TypeError exception" between steps 3 and 4 of 23.1.3.1 (Map.prototype.clear), 23.1.3.3 (Map.prototype.delete), 23.1.3.9 (Map.prototype.set), 23.2.3.1 (Set.prototype.add), 23.2.3.2 (Set.prototype.clear), and 23.2.3.4 (Set.prototype.delete).
> Add `Map.prototype.makeReadOnly()` and `Set.prototype.makeReadOnly()` methods with the definition:
>  1. Let M be the this value.
>  2. If Type(M) is not Object, throw a TypeError exception
>  3. If M does not have a [[Immutable]] internal slot, throw a TypeError exception
>  4. Set the [[Immutable]] internal slot of M to true.

This is somewhat awkward and ad-hoc, but it won't break ES6 code.

I am concerned about this issue in part because as written is seems to be impossible to prevent writes to Map.  If you subclass it, freeze it, override set/delete/etc it is still possible to mutate the map using `Map.set.call(m, 'a', 'b');`.  And there is no way for use code to get at the [[MapData]] slot to protect it.
  --scott


On Thu, Apr 30, 2015 at 2:42 PM, C. Scott Ananian <[hidden email]> wrote:
On Thu, Apr 30, 2015 at 2:22 PM, Mark S. Miller <[hidden email]> wrote:
It would also not be compatible with ES6 code. SES will be freezing Map, Set, WeakMap, and WeakSet instances in order to tamper proof their API. I expect many others will as well. Having this freeze then cause a non-mutability in ES7 will break all such ES6 code. This is a non-starter all around.

Couldn't SES use Object.seal/Object.preventExtensions/Object.defineProperty to perform tamper-proofing without flipping the "frozen" bit?
 --scott




--
    Cheers,
    --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: *.empty Idea

C. Scott Ananian
I like the idea of snapshot methods, but they can be implemented in user code using subclasses in ES6.  I'm particularly interested in the "lock down in place" mechanism because it *cannot* be implemented in user code.

And yes, if we had it all to do over again, it would have been nice if the Map prototype chain was:

Map instance -> Map.prototype -> ReadOnlyMap.prototype -> null

And clear/set/delete were properties of Map.prototype.

But that would still have required an explicit test in Map.clear/set/delete to ensure that they were operating on an instanceof Map and not just on a ReadOnlyMap.
  --scott


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: *.empty Idea

Mark S. Miller-2


On Thu, Apr 30, 2015 at 12:46 PM, C. Scott Ananian <[hidden email]> wrote:
I like the idea of snapshot methods, but they can be implemented in user code using subclasses in ES6.  I'm particularly interested in the "lock down in place" mechanism because it *cannot* be implemented in user code.

And yes, if we had it all to do over again, it would have been nice if the Map prototype chain was:

Map instance -> Map.prototype -> ReadOnlyMap.prototype -> null

And clear/set/delete were properties of Map.prototype.

But that would still have required an explicit test in Map.clear/set/delete to ensure that they were operating on an instanceof Map and not just on a ReadOnlyMap.

Yes, it does not save a test. Rather it only rationalizes the types of objects so that the type of an immutable or readOnly collection does not include useless mutation methods; that's all.


 
  --scott




--
    Cheers,
    --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
12