Extensible destructuring proposal
Isiah Meadows
impinball at gmail.com
Wed Aug 5 07:27:22 UTC 2015
Damnit...forgot to fix the subject.
On Wed, Aug 5, 2015 at 3:20 AM, Isiah Meadows <impinball at gmail.com> wrote:
> Wait...this got me thinking... The proposal itself doesn't bring along a
> lot of merits, but it seems like it could be a great stepping stone to a
> limited pattern matching syntax. This would probably be a little more
> justifiable IMHO than merely a custom destructuring syntax. Maybe something
> like this:
>
> ```js
> Type[Symbol.pattern] = (obj) => {
> return [obj.a, obj.b];
> }
>
> const Other = {
> [Symbol.pattern]: obj => obj,
> }
>
> class None {
> static [Symbol.pattern](obj) {
> return obj
> }
> }
>
> // Pattern matching, signaled by `in` here
> switch (object) in {
> case Type([a, b]): return a + b
> case Other({a, b}): return a * b
> case None: return undefined // Special case, no identifier initialized
> }
>
> // Extensible destructuring, easy to implement with the pattern
> // matching
> let Type([a, b]) = object
> let Other({a, b}) = object
> ```
>
> In the destructuring phase for both, I was thinking about the following
> semantics to assert the type, based on `typeof` and the prototype. This
> will help engines in optimizing this as well as some type safety for all of
> us.
>
> ```js
> function _checkProto(object, Type) {
> // Note: Type[Symbol.pattern] must be callable
> if (typeof Type[Symbol.pattern] !== 'function') throw new TypeError()
> if (typeof Type === 'function') {
> if (type === Array) {
> return Array.isArray(object)
> } else {
> return object instanceof Type
> }
> } else {
> return Object.prototype.isPrototypeOf.call(Type, object)
> }
> }
>
> function isInstance(object, Type) {
> switch (typeof object) {
> case 'object': return obj != null && _checkProto(object, Type)
> case 'function': return Type === Function
> case 'boolean': return Type === Boolean
> case 'number': return Type === Number
> case 'string': return Type === String
> case 'symbol': return Type === Symbol
> case 'undefined': return false
> }
> }
> ```
>
> Finally, get the result and do a basic variable pattern assignment, LHS
> being the operand, and RHS calling `Type[Symbol.pattern]`.
>
> The `switch` statement example would (roughly) desugar to the following:
>
> ```js
> switch (true) {
> case isInstance(object, Type):
> let [a, b] = Type[Symbol.pattern](object)
> return a + b
>
> case isInstance(object, Other):
> let {a, b} = Other[Symbol.pattern](object)
> return a * b
>
> case isInstance(object, None):
> return undefined
> }
> ```
>
> The destructuring examples would (roughly) desugar to this:
>
> ```js
> if (!isInstance(object, Type)) throw new TypeError()
> let [a, b] = Type[Symbol.pattern](object)
> if (!isInstance(object, Other)) throw new TypeError()
> let {a, b} = Other[Symbol.pattern](object)
> ```
>
> The type assertions will help engines in optimizing this, and it'll also
> make this safer. It also just makes sense for pattern matching.
>
> As a side effect, you can get the value without destructuring (i.e. the
> literal result of `Symbol.pattern`) via this:
>
> ```js
> let Map(m) = someMap
> let m = Map[Symbol.pattern](someMap)
> ```
>
> I, myself, came up with a Scala-inspired case class concept
> <https://gist.github.com/impinball/add0b0645ce74214f5aa> based on this,
> and used it to make try-catch handling a little more Promise-like, which I
> know quite a few TypeScript users would eat up in a hurry
> <https://github.com/Microsoft/TypeScript/issues/186> (particularly the
> sum type implementation). I also created a little toy Option/Maybe
> implementation <https://gist.github.com/impinball/4833dc420b60ad0aca73>
> using pattern matching to ease `null`/`undefined` handling.
>
> And also, check out my gist
> <https://gist.github.com/impinball/62ac17d8fa9a20b4d73d> for a proposed
> `Symbol.pattern` prolyfill for the primitive types. That would allow for
> things like this:
>
> ```js
> switch (list) in {
> case Array([a, b, c]): return doSomething(a, b, c)
> case Map({a, b, c}): return doSomethingElse(a, b, c)
> default: return addressBadType(list)
> }
> ```
>
> > ---------- Forwarded message ----------
> > From: Andreas Rossberg <rossberg at google.com>
> > To: "Samuel Hapák" <samuel.hapak at vacuumapps.com>
> > Cc: es-discuss <es-discuss at mozilla.org>
> > Date: Tue, 4 Aug 2015 14:26:45 +0200
> > Subject: Re: Extensible destructuring proposal
> > On 31 July 2015 at 20:09, Samuel Hapák <samuel.hapak at vacuumapps.com>
> wrote:
> >>
> >> So, do you still have objections against this proposal? Could we
> summarize them?
> >>
> >> @Andreas, do you still think that there is category error involved?
> >
> >
> > If you want to overload existing object pattern syntax, then yes,
> definitely. I strongly disagree with that. It breaks regularity and
> substitutability (you cannot pass a map to where a generic object is
> expected).
> >
> > As for a more Scala-like variant with distinguished syntax, I'm fine
> with that semantically. But I still don't buy the specific motivation with
> maps. Can you give a practical example where you'd want to create a map
> (immutable or not) for something that is just a record of statically known
> shape? And explain _why_ you need to do that? Surely it can't be
> immutability, since objects can be frozen, too.
> >
> > To be clear, I wouldn't reject such a feature outright. In fact, in a
> language with abstract data types, "views", as they are sometimes called in
> literature, can be valuable. But they are also notorious for a high
> complexity cost vs minor convenience they typically provide. In particular,
> it is no longer to write
> >
> > let {a: x, b: y} = unMap(map)
> >
> > as you can today, then it would be to move the transformation to the
> pattern:
> >
> > let Map({a: x, b: y}) = map
> >
> > So I encourage you to come up with more convincing examples in the
> JavaScript context. Short of that, I'd argue that the complexity is not
> justified, at least for the time being.
> >
> > /Andreas
>
> --
> Isiah Meadows
>
--
Isiah Meadows
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150805/5340d586/attachment-0001.html>
More information about the es-discuss
mailing list