gkz / LiveScript

LiveScript is a language which compiles to JavaScript. It has a straightforward mapping to JavaScript and allows you to write expressive code devoid of repetitive boilerplate. While LiveScript adds many features to assist in functional style programming, it also has many improvements for object oriented and imperative programming.
http://livescript.net
MIT License
2.31k stars 156 forks source link

Existence check is ignored before object slice access #1102

Closed LeXofLeviafan closed 4 years ago

LeXofLeviafan commented 4 years ago

All of these

(.{foo, bar, baz})
(?{foo, bar, baz})
(?.{foo, bar, baz})
-> it{foo, bar, baz}
-> it.{foo, bar, baz}
-> it?{foo, bar, baz}
-> it?.{foo, bar, baz}

produce exactly the same output:

(function(it){
  return {
    foo: it.foo,
    bar: it.bar,
    baz: it.baz
  };
});

Similarly, every single one of these

(.<[foo bar baz]>)
(?<[foo bar baz]>)
(?.<[foo bar baz]>)
-> it<[foo bar baz]>
-> it.<[foo bar baz]>
-> it?<[foo bar baz]>
-> it?.<[foo bar baz]>
(.[\foo, \bar, \baz])
(?[\foo, \bar, \baz])
(?.[\foo, \bar, \baz])
-> it[\foo, \bar, \baz]
-> it.[\foo, \bar, \baz]
-> it?[\foo, \bar, \baz]
-> it?.[\foo, \bar, \baz]

also produce identical output:

(function(it){
  return [it['foo'], it['bar'], it['baz']];
});

The expected behaviour here, naturally, would be to make an additional nil check when ? is used (or at least produce a compile error if such syntax is not supported).

rhendric commented 4 years ago

Seems like a reasonable thing to want. Can I assume your desired behavior if it is nullish is to return undefinedi.e., have x?{foo} be equivalent to that{foo} if x??

LeXofLeviafan commented 4 years ago

The logical thing here would likely be to do the same as when accessing a single field ((?.foo)), which does indeed behave as you described (though technically the single-field example compiles to it != null ? it.foo : void 8).

rhendric commented 4 years ago

The single-field case is different in that it doesn't create a wrapper object. So maybe x?{foo} should be equivalent to that{foo} if x?, but the alternative would be maybe it's equivalent to { foo: x?foo }; I could see both being doing ‘the same’ as the single-field case, the only difference being whether one conceptually applies the slice desugaring first or the existence desugaring first.

Still think the that{foo} if x? proposal is the most logical thing?

LeXofLeviafan commented 4 years ago

Producing a single undefined is more easily manageable (and makes more sense in general case) than producing a structure filled with undefined values (and is equivalent to maybe-monad behaviour), so yes, short-circuiting at the initial point sounds more reasonable to me.

If you want to have alternative behaviour (object filled with undefined values) available, it could be done with a different syntax (i.e. ? or ?. short-circuits, and .? produces a slice: order defines behaviour), though I doubt you'll find a lot of uses for such output.

rhendric commented 4 years ago

Agreed. If there's anyone out there who wants objects full of undefined, they can ask for that later.

rhendric commented 4 years ago

Actually, on further investigation, this is a regression that I introduced; the 1.5.0 release of LiveScript did exactly this. I'll fix it and add a test.