fail-fast object destructuring

Brendan Eich brendan at mozilla.org
Thu Jul 5 11:14:48 PDT 2012


Andreas Rossberg wrote:
> Well, note my careful use of the conjunctive. :)  That basically was 
> the question I initially asked. My viewpoint is: If there is some 
> reasonable chance that we might add pattern matching at some point in 
> the future, then yes, I think we should not be future hostile, and 
> bear that equivalence in mind as important.
>
>     We could try to have our cake and eat it, by extending the pattern
>     language with prefix-! or prefix-?. Which prefix depends on the
>     choice of default behavior, based on ranking of the two
>     equivalences. Whatever that ranking, does this make sense so far?
>
>
> Sure, I'm all for that. As long as they -- and the rest of the pattern 
> language -- have the same meaning in all contexts.

Ok, we are getting somewhere -- thanks for bearing with me (and I hope 
this thread was helpful to others following, as it was to me).

Then the question is: should we value the current equivalence more and 
make the pattern-matching equivalence use-case pay the prefix-! syntax. 
IOW, keep

A:

   let {foo} = bar();
   =~
   let foo = bar().foo;

and impute undefined if foo is missing in the object returned by bar(), 
and require

   { let {!foo} = exp; console.log(foo) }
   =~
   match (exp) { case !foo; console.log(foo); }

Without the !, the match would bind undefined to the case foo local.

Or should we do as you propose, and require prefix-? to get the 
impute-undefined-on-missing-property behavior needed for the first 
equivalence, call it

B:

   let {?foo} = bar();
   =~
   let foo = bar().foo;

At least this way, match does not need ! to work as pattern-matching 
users expect:

   { let {foo} = exp; console.log(foo) }
   =~
   match (exp) { case foo; console.log(foo); }

Allen rallied me to the prefix-! route by objecting that prefix-? would 
not be available outside of patterns, which simply highlights how JS 
already imputes undefined for missing property.

I feel the burden of the first equivalence acutely, since I implemented 
destructuring per the ES4-era proposal to look like (A) above, based on 
Opera's engine of the time, and Rhino and probably other engines 
followed suit. This experience means compatibility breaking pain, and 
what's more: user-testing something new, unscientifically as ever but in 
much less time than we've had to hear about bugs due to (A).

However, I agree that requiring prefix-! in

  match (exp) { case !foo: ... }

is onerous if we choose the impute-undefined path, and worse: that a 
missing prefix-! is both likely to happen (a footgun), and nonsensical 
for pattern matching.

So (B) wins if we want pattern-matching.

We should talk more at this month's TC39 meeting, but I see a sharp 
divide ahead:

1. Choose (A), possibly with modification, either rejecting useful 
pattern matching decisively, or else making its pattern language differ 
by making prefix-! implicit. But you rejected splitting pattern meaning 
across destructuring and future pattern-matching, in the last sentence 
cited above.

XOR

2. Choose (B) because future-proofing for pattern matching wants 
prefix-?, and impose a compatibility break from what we and others 
implemented, and what most JS users might expect based on JS's carefree 
imputing of undefined.

Comments from es-discuss peanut gallery welcome.

I could go for 1/A, except for two facts. First, I believe there is a 
non-trivial body of Firefox JS that depends on imputing undefined. 
Second, and what is more important: we haven't usability-tested 2/B at all.

/be



More information about the es-discuss mailing list