es-discuss Digest, Vol 102, Issue 14

Isiah Meadows impinball at
Wed Aug 5 07:20:02 UTC 2015

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:

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

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)

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:

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:

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:

let Map(m) = someMap
let m = Map[Symbol.pattern](someMap)

I, myself, came up with a Scala-inspired case class concept
<> 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
<> (particularly the sum
type implementation). I also created a little toy Option/Maybe
implementation <>
using pattern matching to ease `null`/`undefined` handling.

And also, check out my gist
<> for a proposed
`Symbol.pattern` prolyfill for the primitive types. That would allow for
things like this:

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>
> To: "Samuel Hapák" <samuel.hapak at>
> Cc: es-discuss <es-discuss at>
> 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>
>> 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
> 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
>   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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the es-discuss mailing list