Overriding Map/etc with get/set hooks?

Ron Buckton rbuckton at chronicles.org
Tue May 21 21:20:18 PDT 2013

What if the default Map prototype had a configurable but non-writable data property for a @@coerceKey symbol that pointed to a default coercion function. You could subclass Map and provide your own @@coerceKey implementation. Then Map.prototype.set.call() would be forced to run the custom coercion function.

A @@coerceKey override could be used to coerce keys from one type to another, or to provide key validation if you want keys in a specific format. By providing a default implementation that is basically an identity function, you maintain the same current expectations for Map. This then gives developers the ability to further customize the behavior of Map in subclasses, giving the class more flexibility.

If that were the case, there could also be a @@coerceValue symbol on Map.prototype as well as Set.prototype. Possibly even Array.prototype as well for Array subclasses, as a means of limiting array contents to a specific type. The coercion functions could also be used to allow a subclass to Mark itself as read-only and throw on attempts at modification. Default implementations could verify whether the coercion function has changed from the default and skip the coercion calls as a performance optimization.


Sent from Windows Mail

From: Tab Atkins Jr.
Sent: ‎Tuesday‎, ‎May‎ ‎21‎, ‎2013 ‎10‎:‎53‎ ‎AM
To: Sam Tobin-Hochstadt
Cc: Brendan Eich, es-discuss

On Tue, May 21, 2013 at 7:19 AM, Sam Tobin-Hochstadt <samth at ccs.neu.edu> wrote:
> On Tue, May 21, 2013 at 6:52 AM, Anne van Kesteren <annevk at annevk.nl> wrote:
>> On Tue, May 21, 2013 at 12:19 PM, Brendan Eich <brendan at mozilla.com> wrote:
>>> Of course, coercing key type makes the API not Map. So if the
>>> bi-directionality is important, this would be a custom Map-like class.
>> I guess I also do not really get this. Sure JavaScript does not have a
>> type system (yet?), but it seems that placing restrictions / coercion
>> on input does not invalidate any of the properties of a map other than
>> that there's a restriction on what goes in the map. To me that seems
>> very much like a subset of a map and all generic functionality written
>> around maps would work on such a map.
> The following function returns true for all Maps M, Strings k, and JS values v:
> function check(M, k, v) {
>    M.set(k,v);
>    return (v === M.get(k));
> }
> In fact, this is the essence of what Maps are about.  Your proposal
> doesn't have this property. Therefore, it shouldn't be a Map.

Within the type constraints we enforce, this is maintained.  That is,
if you use string keys and values, it maintains *all* of the Map
invariants.  If you use non-string keys or values, we coerce to a
string first, so the invariants may not hold in all circumstances.
That's the point of coercion.

This argument is like saying that, if "p.foo = obj; p.foo === obj;"
isn't maintained, then "p" isn't an Object and should be something
else.  In reality, we're completely fine with "foo" being a getter or
setter with arbitrary effects; in particular, it can apply coercion
rules, which is rather common on the web.

If TC39 isn't going to allow us to ever use *any* of the built-in
collection classes just because we have type restrictions we need to
enforce, that'll be a pretty raw deal for authors.  It'll just mean we
continue with our "custom, shitty, incompatible versions of all your
standard collections" thing that we've been doing for some time. (And
never doubt, for each collection you have, we'll have N slightly
incompatible versions, where N is proportional to the number of specs
that use something like the collection.)

> The analogy to NodeList is actually valuable -- NodeLists are pretty
> different from Arrays, but some of the array generics work on them. If
> the problem is that the Map functions should be more generic, that's
> something that could be fixed, but that doesn't mean we should pretend
> that things are maps when they aren't.

Making the methods more generic won't help much (though it would
probably help *slightly*) - the problem is that the methods *aren't on
the objects*.  Try to guess the relative numbers of people who do
"Array.prototype.forEach.call(arrayLike, ...)" versus the numbers who
just do a quick "Array.prototype.slice.call(arrayLike)" at the
beginning and then rejoice at having a real Array to use.

We need to fix this "type coercion means it's not one of ours"
problem, now.  It's not good for authors or for the platform as a

es-discuss mailing list
es-discuss at mozilla.org

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20130522/b851cf4c/attachment.html>

More information about the es-discuss mailing list