On 5 August 2015 at 09:27, Isiah Meadows <[email protected]> wrote:
> Damnit...forgot to fix the subject. > > On Wed, Aug 5, 2015 at 3:20 AM, Isiah Meadows <[email protected]> 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: >> > I intentionally did not bring up pattern matching. That indeed is what views are usually wanted for. But then you need to be much more careful in designing a mechanism that avoids re-transforming the scrutinee for every tested case! Because that would be very costly. For that reason, I fear that the feature as proposed would interact badly with any future pattern matching mechanism, in the sense that it would encourage very costly usage that cannot be optimised. /Andreas > >> ```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 <[email protected]> >> > To: "Samuel Hapák" <[email protected]> >> > Cc: es-discuss <[email protected]> >> > Date: Tue, 4 Aug 2015 14:26:45 +0200 >> > Subject: Re: Extensible destructuring proposal >> > On 31 July 2015 at 20:09, Samuel Hapák <[email protected]> >> 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 >
_______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

