Extensible destructuring proposal
Isiah Meadows
isiahmeadows at gmail.com
Thu Aug 6 18:21:41 UTC 2015
I meant "statically compiled" in the sense of AOT compiled, in the veins of
C++, Java, TypeScript, etc.
On Wed, Aug 5, 2015, 14:04 Brendan Eich <brendan at mozilla.org> wrote:
> Missing reply text? Your message which you cited in full made it to the
> list.
>
> BTW "statically compiled" doesn't make sense -- did you mean "statically
> typed", or "with fully static name binding"? JS does lack those,
> although strict mode gets close to fully static name binding (the global
> object can still sprout new properties that may be referenced via free
> variables).
>
> /be
>
> Isiah Meadows wrote:
> >
> >
> >
> > On Wed, Aug 5, 2015, 04:29 Isiah Meadows <impinball at gmail.com
> > <mailto:impinball at gmail.com>> wrote:
> >
> > Good point. I did make most of the natives identity functions
> > returning the object itself for most cases with the prolyfill,
> > which engines should easily detect at run time and inline into
> > nothingness. But I do see your point. As proposed, I know it's
> > still incomplete in its core functionality (pattern matching on
> > array literals would be a bit more interesting), but the other
> > core problem is this: JavaScript isn't statically compiled. Nearly
> > every language with patten matching is. It's much easier to
> > optimize this into something decently performant in a static
> > context (TypeScript as an example).
> >
> >
> > On Wed, Aug 5, 2015, 04:19 Andreas Rossberg <rossberg at google.com
> > <mailto:rossberg at google.com>> wrote:
> >
> > On 5 August 2015 at 09:27, Isiah Meadows <impinball at gmail.com
> > <mailto:impinball at gmail.com>> wrote:
> >
> > Damnit...forgot to fix the subject.
> >
> > On Wed, Aug 5, 2015 at 3:20 AM, Isiah Meadows
> > <impinball at gmail.com <mailto: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:
> >
> >
> > 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 <rossberg at google.com
> > <mailto:rossberg at google.com>>
> > > To: "Samuel Hapák" <samuel.hapak at vacuumapps.com
> > <mailto:samuel.hapak at vacuumapps.com>>
> > > Cc: es-discuss <es-discuss at mozilla.org
> > <mailto: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
> > <mailto: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
> >
> > _______________________________________________
> > 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/20150806/e7c7c118/attachment-0001.html>
More information about the es-discuss
mailing list