Map literal

Tab Atkins Jr. jackalmage at
Sun Nov 29 03:22:17 UTC 2015

On Thu, Oct 29, 2015 at 6:23 PM, Alexander Jones <alex at> wrote:
> I don't think borrowing object notation is a good idea. What exactly does
> ```
> const myMap = Map#{
>     get foo() { return 100; },
>     set foo(v) {}
>     constructor() {}
> };
> ```
> mean?
> Honestly, a very significant portion of the use cases I have for *actual
> maps* don't involve string keys. So to borrow object notation and have to
> constantly write keys in [] is pretty naff:
> ```
> const describe = Dict#{
>     [1]: "one",
>     [[1, 2]]: "array of 1 and 2",
>     [null]: "the null value",
> }; // please no!
> ```
> If it makes people feel too weird to have comma separated, colon split
> key-value pairs within curlies that *don't* parse like POJSOs, we could have
> completely non-ambiguous parse with normal parentheses, I think?
> ```
> const describe = Dict#(
>     1: "one",
>     [1, 2]: "array of 1 and 2",
>     null: "the null value",
> );
> ```
> That might limit confusion while giving a syntactically clean way to define
> maps. Let's consider that a future mapping type like Dict compares
> non-primitive keys by abstract value instead of by reference identity. There
> are *tonnes* of nice use cases that open up that are taken for granted in
> other languages and other classes like Immutable.Map - we're not there yet
> with ES6 built-ins, so perhaps people might not yet appreciate the value of
> this.
> To reiterate a previous point, object property access with a statically
> defined string key is idiomatically written ``, so it makes sense for
> symmetry to have `foo` appear as a bareword in a literal defining `obj =
> {foo: 42}`. For most mapping-type classes this symmetry simply does not
> apply, and frankly neither should it.
> Also, I specifically suggested that the consumed value is an ArrayIterator
> rather than an Array, because I feel having an intermediate Array around is
> placing too high an importance on the humble Array. If the implementation
> really wants an Array to work on internally, they can simply call
> `Array.from` with little cost. But if they want an Immutable.List they can
> have that instead without ever seeing an actual Array. (The Symbol.fromHash
> method is just Symbol.literalOf as I called it - same thing, modulo
> bikeshed.)

I strongly agree with a lot of the points here, and think they suggest
the OP's suggestion was generalized in slightly the wrong way.
Producing a Map literal is indeed too specific to justify syntax, but
what's suggested is not a special way of calling some constructors,
but *a literal syntax for 2-value iterators*.

We have a literal syntax for 1-value iterators: just use an Array.
It's lightweight (2 chars + 1 char per item), and typos in the syntax
are caught at compile time.  Our existing literal syntax for 2-value
iterators (an array of length-2 arrays) fails at both of these: it's
heavyweight (4 chars + 4 chars per item), and typos in the syntax are
only caught at runtime, when it's actually iterated over.

Having a lightweight, compile-time-checked 2-value iterator literal
that desugars to an N×2 Array (or ArrayIterator) fixes all these
problems, and makes it easy to write Map literals, Immutable.Dict
literals, or anything else.  Using the hash-paren syntax suggested

let m =  Map(#(1: "one", [1, 2]: "array of 1 and 2", null: "the null value"));

There's no need to invent a new function-calling syntax or add a new
well-known symbol to anything. It Just Works™ as long as the function
you pass it to expects a 2-value iterator.

(From other languages, there doesn't appear to be any call for N×3
literals or anything higher


More information about the es-discuss mailing list