Mark S. Miller (2015-04-30T19:15:13.000Z)
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 <ecmascript at cscott.net>
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 <ecmascript at cscott.net>
> wrote:
>
>> On Thu, Apr 30, 2015 at 2:22 PM, Mark S. Miller <erights at google.com>
>> 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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150430/03d8feb6/attachment.html>
d at domenic.me (2015-05-11T16:56:34.359Z)
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

```js
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.