Map literal
Isiah Meadows
isiahmeadows at gmail.com
Fri Oct 30 09:57:24 UTC 2015
That's something no one here really thought of yet. I don't personally have
a lot of investment in this.
(@Alex and yes, much of that was based on your idea. It was a great
starting point.)
On Thu, Oct 29, 2015, 21:23 Alexander Jones <alex at weej.com> 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 `obj.foo`, 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.)
>
> Alex
>
>
> On 29 October 2015 at 22:51, Isiah Meadows <isiahmeadows at gmail.com> wrote:
>
>> Why not make it desugar to a direct function call with a single array of
>> pairs? It's so parsed as a regular object, so shorthands can still be used.
>>
>> `Map#{foo: 1, bar: 2, 3: "baz"}`
>> `Map[Symbol.fromHash]([[foo", 1], ["bar", 2], ["3", "baz]])`
>>
>> `Object#{foo: 1, bar: 2, 3: "baz"}`
>> `Object[Symbol.fromHash]([[foo", 1], ["bar", 2], ["3", "baz]])`
>>
>> `Object.null#{foo: 1, bar: 2, 3: "baz"}`
>> `Object.null[Symbol.fromHash]([[foo", 1], ["bar", 2], ["3", "baz]])`
>>
>> (`bar` doesn't have [[Construct]])
>> `Object#{foo, bar() {}}`
>> `Object[Symbol.fromHash]([[foo", foo], ["bar", function () {}]])`
>>
>> And as for implementation, use this:
>>
>> ```js
>> extend class Map {
>> static [Symbol.fromHash](pairs) {
>> return new this(pairs);
>> }
>> }
>>
>> // etc...
>>
>> function SetKeys(target, pairs) {
>> for (const [key, value] of pairs) {
>> target[key] = value
>> }
>> return target
>> }
>>
>> extend class Object {
>> static [Symbol.fromHash](pairs) {
>> return SetKeys({}, pairs)
>> }
>>
>> static null(pairs) {
>> return SetKeys(Object.create(null), pairs)
>> }
>> }
>> ```
>>
>> Pretty simple IMHO. A helper decorator could even be made.
>>
>> On Wed, Oct 28, 2015, 14:34 Alexander Jones <alex at weej.com> wrote:
>>
>>> Also I would like to reiterate that errors in the shape of the N-by-2
>>> array are only caught at runtime. That's really not ideal.
>>>
>>> On Wednesday, 28 October 2015, Dave Porter <david_porter at apple.com>
>>> wrote:
>>>
>>>> I don’t love any of the specific suggestions so far, but saving 3 + 2n
>>>> keystrokes isn't the point – readability and learnability are. Visually,
>>>> `new Map([[‘foo’, 42]])` is a mess.
>>>>
>>>> On Oct 28, 2015, at 9:28 AM, Michał Wadas <michalwadas at gmail.com>
>>>> wrote:
>>>>
>>>> Difference between any proposed here syntax and current state ( new
>>>> Map([ [1,2], [2,3] ]); ) is..
>>>>
>>>> 3 characters + 2 characters/entry.
>>>>
>>>>
>>>>
>>>>
>>>> 2015-10-28 17:22 GMT+01:00 Mohsen Azimi <me at azimi.me>:
>>>>
>>>>> When I look at `Map#{"foo": 42}` I don't see much difference with `new
>>>>> Map([['foo', 42]])`.
>>>>>
>>>>> Since you can pass expressions there, it's already possible to do it
>>>>> with current syntax. There is only a bunch of extra brackets(`[` and `]`)
>>>>> that I don't like.
>>>>>
>>>>>
>>>>> On Wed, Oct 28, 2015 at 5:51 AM Alexander Jones <alex at weej.com> wrote:
>>>>>
>>>>>> Ah, there is actually a good case for keeping barewords in object
>>>>>> literals but removing them from map literals, and that's due to objects
>>>>>> accessing string properties as bare words, too. This is almost never the
>>>>>> case for other map types.
>>>>>>
>>>>>> ```
>>>>>> const o = {foo: 42};
>>>>>> o.foo === 42;
>>>>>> o.bar = 43;
>>>>>>
>>>>>> const m = Map#{"foo": 42};
>>>>>> m.get("foo") === 42;
>>>>>> m.set("bar", 43);
>>>>>> ```
>>>>>>
>>>>>> Would you agree?
>>>>>>
>>>>>>
>>>>>> On Wednesday, 28 October 2015, Alexander Jones <alex at weej.com> wrote:
>>>>>>
>>>>>>> Hi Herby
>>>>>>>
>>>>>>> Agree with your concerns about symmetry with object literals, but
>>>>>>> many of the uses of maps benefit from having non string keys, and in such
>>>>>>> case generally everything would involve wrapping in []. Trying to use an
>>>>>>> Array as a key would be quite ugly with the extra squares required
>>>>>>>
>>>>>>> ```
>>>>>>> const precachedResults = MyMap#{[[1, 2, 3]]: [1, 4, 9]}
>>>>>>> vs
>>>>>>> const precachedResults = MyMap#{[1, 2, 3]: [1, 4, 9]}
>>>>>>> ```
>>>>>>>
>>>>>>> Perhaps a middle ground could be that if you want to use an
>>>>>>> expression that would otherwise be a bare word, you enclose in parens. The
>>>>>>> visual binding of the colon is deceptive anyway, so I tend to do this if
>>>>>>> the key expression contains a space:
>>>>>>>
>>>>>>> ```
>>>>>>> MyMap#{1 + 2 + 3: 6}
>>>>>>> vs.
>>>>>>> MyMap#{(1 + 2 + 3): 6}
>>>>>>> ```
>>>>>>>
>>>>>>> But I think I still prefer that the parsing for the key part is just
>>>>>>> standard expression evaluation, personally, and the POJSO literal barewords
>>>>>>> remain the only special case.
>>>>>>>
>>>>>>> Indeed,
>>>>>>>
>>>>>>> ```
>>>>>>> Object#{1: "one", Symbol(): "sym"}
>>>>>>> ```
>>>>>>>
>>>>>>> Could Object-key-ify the keys, i.e. turn them into strings if not
>>>>>>> symbols, and Just Work (but a default implementation on the Object
>>>>>>> prototype is questionable!). That said I'm not sure we should be using
>>>>>>> Object for this kind of thing. At this point I don't know what a raw
>>>>>>> `#{}` should produce... There may be a better use case for it in the
>>>>>>> future, horrible ASI complexities notwithstanding.
>>>>>>>
>>>>>>> Alex
>>>>>>>
>>>>>>>
>>>>>>> On Wednesday, 28 October 2015, Herby Vojčík <herby at mailbox.sk>
>>>>>>> wrote:
>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> Alexander Jones wrote:
>>>>>>>>
>>>>>>>>> Ok, thanks for clarifying. Not only does it preserve order but it
>>>>>>>>> also
>>>>>>>>> permits non-string keys. You're still missing one detail which is
>>>>>>>>> that
>>>>>>>>> `bar` would actually be a variable not a string key.
>>>>>>>>>
>>>>>>>>> Another example to clarify that the key part would be an
>>>>>>>>> expression:
>>>>>>>>>
>>>>>>>>> ```
>>>>>>>>> Map#{foo(42) + 7: "bar"}
>>>>>>>>> ```
>>>>>>>>>
>>>>>>>>> I prefer this over the precedent set by object literals which would
>>>>>>>>> require that [] are used around a key expression ("computed key")
>>>>>>>>> simply
>>>>>>>>>
>>>>>>>>
>>>>>>>> I, on the other hand, think it should match object literals
>>>>>>>> completely. So your example would be
>>>>>>>>
>>>>>>>> ```
>>>>>>>> Map#{[foo(42)+7]: "bar"}
>>>>>>>> ```
>>>>>>>>
>>>>>>>> Yes, it's just for consistency and less WTF moment while learning
>>>>>>>> the details.
>>>>>>>>
>>>>>>>> OTOH, there could be consistent contraproposal of:
>>>>>>>>
>>>>>>>> ```
>>>>>>>> Object#{foo(42) + 7: "bar"}
>>>>>>>> null#{foo(42) + 7: "bar"}
>>>>>>>> #{foo(42) + 7: "bar"}
>>>>>>>> ```
>>>>>>>>
>>>>>>>> where the first is equivalent to {[foo(42)+7]: "bar"}, the second
>>>>>>>> is pure container (Object.create(null)) filled with properties, and the
>>>>>>>> third is the default case, but I don't know which of the previous two - the
>>>>>>>> first is probably less confusing, though the feels more clean.
>>>>>>>>
>>>>>>>> due to relieving the syntax noise, which is what this idea is all
>>>>>>>>> about.
>>>>>>>>> Also, this is how it works in Python and I make no apologies about
>>>>>>>>> the
>>>>>>>>> similarities ;)
>>>>>>>>>
>>>>>>>>> Alex
>>>>>>>>>
>>>>>>>>> On Wednesday, 28 October 2015, Viktor Kronvall
>>>>>>>>> <viktor.kronvall at gmail.com <mailto:viktor.kronvall at gmail.com>>
>>>>>>>>> wrote:
>>>>>>>>>
>>>>>>>>> Hello Alexander,
>>>>>>>>>
>>>>>>>>> I see now that I misread your desugaring.
>>>>>>>>>
>>>>>>>>> I read:
>>>>>>>>>
>>>>>>>>> ```
>>>>>>>>> Map#{1: 6, bar: 'Hello', 2: 8};
>>>>>>>>> ```
>>>>>>>>> as being desugared to:
>>>>>>>>>
>>>>>>>>> ```
>>>>>>>>> Map[Symbol.literalOf]({1: 6, bar: 'Hello', 2:
>>>>>>>>> 8}[Symbol.iterator]());
>>>>>>>>> ```
>>>>>>>>>
>>>>>>>>> But your proposal clearly states that is should be:
>>>>>>>>>
>>>>>>>>> ```
>>>>>>>>> Map[Symbol.literalOf]([[1, 6], ['bar', 'Hello'],
>>>>>>>>> [2,8]][Symbol.iterator]());
>>>>>>>>> ```
>>>>>>>>>
>>>>>>>>> Which would preserve lexical ordering of entries. The fault is
>>>>>>>>> completely mine. Sorry.
>>>>>>>>>
>>>>>>>>> I like this proposal as it is extensible and not that noisy in
>>>>>>>>> syntax. Using the `#` for this doesn't
>>>>>>>>> seem like a bad idea either. People coming from Erlang will be
>>>>>>>>> familiar with this as well.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> 2015-10-28 10:53 GMT+01:00 Alexander Jones <alex at weej.com
>>>>>>>>> <javascript:_e(%7B%7D,'cvml','alex at weej.com');>>:
>>>>>>>>>
>>>>>>>>> Hi Victor
>>>>>>>>>
>>>>>>>>> Not sure I understand - the desugaring I wrote would
>>>>>>>>> absolutely
>>>>>>>>> preserve the written ordering because it speaks in terms
>>>>>>>>> of an
>>>>>>>>> ArrayIterator of key-value pairs. If the map type to which
>>>>>>>>> it's
>>>>>>>>> applied chooses to forget the ordering then that's fine.
>>>>>>>>>
>>>>>>>>> Alex
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On Wednesday, 28 October 2015, Viktor Kronvall
>>>>>>>>> <viktor.kronvall at gmail.com
>>>>>>>>> <javascript:_e(%7B%7D,'cvml','viktor.kronvall at gmail.com');>>
>>>>>>>>> wrote:
>>>>>>>>>
>>>>>>>>> > ```
>>>>>>>>> > const map = IMap#{"foo": 42, bar: 44};
>>>>>>>>> > ```
>>>>>>>>> > It could desugar as, for the sake of example:
>>>>>>>>> >
>>>>>>>>> > ```
>>>>>>>>> > Foo#{key: value, ...}
>>>>>>>>> > ➔
>>>>>>>>> > Foo[Symbol.literalOf]([[key, value],
>>>>>>>>> ...][Symbol.iterator]())
>>>>>>>>> > ```
>>>>>>>>>
>>>>>>>>> I like this proposal. However, Maps should guarantee
>>>>>>>>> insertion order when traversing the keys and values and
>>>>>>>>> desugaring it like that does not respect this
>>>>>>>>> guarantee or
>>>>>>>>> more precisely it will lead to (in my opinion)
>>>>>>>>> unexpected
>>>>>>>>> order of the keys.
>>>>>>>>>
>>>>>>>>> ```
>>>>>>>>> Object.keys({1: 6, bar: 'Hello', 2: 8}); // → [ '1',
>>>>>>>>> '2',
>>>>>>>>> 'bar' ]
>>>>>>>>> ```
>>>>>>>>>
>>>>>>>>> If I'm not mistaken this will be same order for `{1:
>>>>>>>>> 6, bar:
>>>>>>>>> 'Hello', 2: 8}[Symbol.iterator]()`.
>>>>>>>>>
>>>>>>>>> This implies that:
>>>>>>>>>
>>>>>>>>> ```
>>>>>>>>> Map#{1: 6, bar: 'Hello', 2: 8};
>>>>>>>>> ```
>>>>>>>>>
>>>>>>>>> Will not have entries in the order `[[1, 6], ['bar',
>>>>>>>>> 'Hello'], [2,8]]` but instead `[[1,6], [2,8],
>>>>>>>>> ['bar','Hello']]`.
>>>>>>>>>
>>>>>>>>> This means that possible future destructuring of a Map
>>>>>>>>> will
>>>>>>>>> be harder to reason about.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> 2015-10-28 2:21 GMT+01:00 Alexander Jones <
>>>>>>>>> alex at weej.com>:
>>>>>>>>>
>>>>>>>>> True, but easy to mess up and only be treated to a
>>>>>>>>> runtime error. Three nested brackets at the start
>>>>>>>>> and
>>>>>>>>> end could definitely be better, and this just
>>>>>>>>> encourages
>>>>>>>>> people to use POJSOs instead. Also not a very
>>>>>>>>> uniform
>>>>>>>>> interface if you look at how to construct a Map,
>>>>>>>>> Set or
>>>>>>>>> Immutable.List at present, though admittedly
>>>>>>>>> constructor
>>>>>>>>> call for the ES6 types would be a partial
>>>>>>>>> improvement.
>>>>>>>>>
>>>>>>>>> On Wednesday, 28 October 2015, Tab Atkins Jr.
>>>>>>>>> <jackalmage at gmail.com> wrote:
>>>>>>>>>
>>>>>>>>> On Wed, Oct 28, 2015 at 8:36 AM, Alexander
>>>>>>>>> Jones
>>>>>>>>> <alex at weej.com> wrote:
>>>>>>>>> > I agree this is pretty important. Using
>>>>>>>>> actual
>>>>>>>>> maps really frees up a lot of
>>>>>>>>> > complexity, but the syntax is cumbersome to
>>>>>>>>> say
>>>>>>>>> the least.
>>>>>>>>> >
>>>>>>>>> > Whatever the decided syntax, bare words as
>>>>>>>>> string
>>>>>>>>> keys is a really bad idea
>>>>>>>>> > IMO. The key syntax should be parsed as an
>>>>>>>>> expression, like the values are,
>>>>>>>>> > and like they are in basically every other
>>>>>>>>> language.
>>>>>>>>> >
>>>>>>>>> > Another outstanding issue is that we might
>>>>>>>>> want
>>>>>>>>> the syntax for
>>>>>>>>> > `Immutable.Map`, or `WeakMap`, or
>>>>>>>>> `MapTwoPointOh`
>>>>>>>>> that improves deficiency
>>>>>>>>> > $x, $y and $z. I'd say introducing a special
>>>>>>>>> syntax for `Map` right now is
>>>>>>>>> > not ideal.
>>>>>>>>>
>>>>>>>>> Currently, the "extensible literal syntax" for
>>>>>>>>> this
>>>>>>>>> isn't that bad:
>>>>>>>>>
>>>>>>>>> const bar = 43;
>>>>>>>>> const map = Immutable.Map([["foo", 42], [bar,
>>>>>>>>> 44]]);
>>>>>>>>>
>>>>>>>>> It's a little more verbose because the entries
>>>>>>>>> have
>>>>>>>>> to be surrounded
>>>>>>>>> by [], but hey.
>>>>>>>>>
>>>>>>>>> ~TJ
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> _______________________________________________
>>>>>>>>> es-discuss mailing list
>>>>>>>>> es-discuss at mozilla.org
>>>>>>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> _______________________________________________
>>>>>>>>> es-discuss mailing list
>>>>>>>>> es-discuss at mozilla.org
>>>>>>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>>>>>>
>>>>>>>> _______________________________________________
>>>>>> es-discuss mailing list
>>>>>> es-discuss at mozilla.org
>>>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>>>
>>>>>
>>>>> _______________________________________________
>>>>> es-discuss mailing list
>>>>> es-discuss at mozilla.org
>>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>>
>>>>>
>>>> _______________________________________________
>>>> es-discuss mailing list
>>>> es-discuss at mozilla.org
>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>
>>>>
>>>> _______________________________________________
>>> es-discuss mailing list
>>> es-discuss at mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20151030/3fce1312/attachment-0001.html>
More information about the es-discuss
mailing list