Refutable destructuring

# Axel Rauschmayer (12 years ago)

AFAICT, there is no current consensus on whether destructuring assignment is refutable by default or not: rwldrn/tc39-notes/blob/master/es6/2013-07/july-23.md#44-consider-deferring-es6-refutable-matching

Could we make destructuring assignment fail soft and introduce a marker for refutable parts of a pattern (e.g. a prefix !):

let { !a: foo, b: bar } = { a: 1 };  // ok: foo = 1, b = undefined
let { !a: foo, b: bar } = { };  // exception

This would have one advantage: It would be possible to bring this operator to parameter declarations (allowing one to declaratively specify a minimum arity). Then destructuring assignment and parameter handling would work very similarly.

function bla(!mandatoryArg, optionalArg1, optionalArg2 = 123) {
    ...
}
# Domenic Denicola (12 years ago)

Woah. I was sad about the loss of refutable destructuring, i.e. I would rather have had it by default, but this idea is a pretty brilliant way to make lemonade out of lemons. I would love a way to declaratively specify required parameters.

# Rick Waldron (12 years ago)

While I agree this is interesting and should be explored further, I reject the proposal to add more meaning to the "!" character. Given this proposal, "!" would sometimes mean "not" or "negate" (as in it's current form) and sometimes mean "a required thing". Meanwhile, "refute" is a synonym for "negate", which is the opposite of what you're claiming the semantics would be, ie. irrefutable, "impossible to omit" or "impossible to deny [a value for this identifier binding]".

# Axel Rauschmayer (12 years ago)

While I agree this is interesting and should be explored further, I reject the proposal to add more meaning to the "!" character. Given this proposal, "!" would sometimes mean "not" or "negate" (as in it's current form) and sometimes mean "a required thing". Meanwhile, "refute" is a synonym for "negate", which is the opposite of what you're claiming the semantics would be, ie. irrefutable, "impossible to omit" or "impossible to deny [a value for this identifier binding]".

I agree. + may be a better choice (reminiscent of regular expressions as opposed to the boolean operator). Then the code becomes:

let { +a: foo, b: bar } = { a: 1 };  // foo = 1, b = undefined
let { +a: foo, b: bar } = { };  // exception

function bla(+mandatoryArg, optionalArg1, optionalArg2 = 123) {
    ...
}
# Brendan Eich (12 years ago)

On Aug 9, 2013, at 3:32 PM, Rick Waldron <waldron.rick at gmail.com> wrote:

While I agree this is interesting and should be explored further, I reject the proposal to add more meaning to the "!" character. Given this proposal, "!" would sometimes mean "not" or "negate" (as in it's current form) and sometimes mean "a required thing". Meanwhile, "refute" is a synonym for "negate", which is the opposite of what you're claiming the semantics would be, ie. irrefutable, "impossible to omit"

No.

or "impossible to deny [a value for this identifier binding]".

No, refutable is what Axel means. He wants matching, so a failure or refutation to cause fall through to next match. What we have in JS now with o.p and in ES6 with let {p} = o; is irrefutable -- no way to mismatch, if the property is missing you get undefined.

So ! Is not too far off the mark. Recall that the late proposal was to unify patterns used now in destructuring and later in matching by requiring ? for irrefutability and making lack of ? mean "refutable".

# Brandon Benvie (12 years ago)

On 8/9/2013 3:36 PM, Axel Rauschmayer wrote:

let { +a: foo, b: bar } = { a: 1 };  // foo = 1, b = undefined
let { +a: foo, b: bar } = { };  // exception

function bla(+mandatoryArg, optionalArg1, optionalArg2 = 123) {
    ...
}

I presume these would also be valid, and do the expected:

function foo({ +bar }){ }
function foo2([+bar2]){ }
# Allen Wirfs-Brock (12 years ago)

On Aug 9, 2013, at 2:58 PM, Domenic Denicola wrote:

Woah. I was sad about the loss of refutable destructuring, i.e. I would rather have had it by default, but this idea is a pretty brilliant way to make lemonade out of lemons. I would love a way to declaratively specify required parameters.

const MUST = () => {throw TypeError("Missing required parameter"};

function foo (a=MUST(), b, c) {...}
# Rick Waldron (12 years ago)

On Fri, Aug 9, 2013 at 6:40 PM, Brendan Eich <brendan at mozilla.com> wrote:

No, refutable is what Axel means. He wants matching, so a failure or refutation to cause fall through to next match. What we have in JS now with o.p and in ES6 with let {p} = o; is irrefutable -- no way to mismatch, if the property is missing you get undefined.

So ! Is not too far off the mark. Recall that the late proposal was to unify patterns used now in destructuring and later in matching by requiring ? for irrefutability and making lack of ? mean "refutable".

My argument was specifically about the current meaning of the ascii exclamation "!" and that assigning it an additional context-based meaning that's quite the opposite of the current unary operator meaning, isn't a proposal that I would support. This is stated with no regard for previous refutable matching proposals.

# Brandon Benvie (12 years ago)

On 8/9/2013 4:03 PM, Allen Wirfs-Brock wrote:

const MUST = () => {throw TypeError("Missing required parameter"};

function foo (a=MUST(), b, c) {...}

But that doesn't work for:

function foo({ a } = { a: MUST() }){}
foo({}); // doesn't throw

function bar({ +a }){}
bar({}); // would throw
# Allen Wirfs-Brock (12 years ago)

On Aug 9, 2013, at 4:21 PM, Brandon Benvie wrote:

But that doesn't work for:

function foo({ a } = { a: MUST() }){}

this would expressed as:

function foo( {a=MUST() }) {}
foo({}); // doesn't throw

then the above throws and so does

foo()
# Allen Wirfs-Brock (12 years ago)

On Aug 9, 2013, at 5:37 PM, Allen Wirfs-Brock wrote:

this would expressed as:

function foo( {a=MUST() }) {}

and if we make U+2639 a special token that evaluated to throw TypeError we could say

function foo( {a=☹ }) {}

;-)

# Brandon Benvie (12 years ago)

On 8/9/2013 5:45 PM, Allen Wirfs-Brock wrote:

and if we make U+2639 a special token that evaluated to throw TypeError we could say

function foo( {a=☹ }) {}

This would be awesome.

# Brendan Eich (12 years ago)

Rick Waldron wrote:

My argument was specifically about the current meaning of the ascii exclamation "!" and that assigning it an additional context-based meaning that's quite the opposite of the current unary operator meaning,

Ok, and I'm with you (recall Mark M. wants ! as restricted-production binary operator for promises), but you still swapped refutable and irrefutable :-P.

isn't a proposal that I would support. This is stated with no regard for previous refutable matching proposals.

Right, but remember: the kind of destructuring that imputes undefined for missing property is irrefutable. Can't refute so can't mismatch so can't fall thru to later match-case. That's all I wanted to get across ;-).

# Brian Di Palma (12 years ago)

It looks to me like there are people who want a sort of ducktypeof operator.

arg1 ducktypeof MyClass

Which would return true if the shape of arg1 where the same as MyClass. If I wanted to write as a refutable pattern I could end up with a large block that may be repeated in several class methods.

It would be nice to shorten that so that you could declare tersely that your methods require a specific shape to be passed in.

# Brendan Eich (12 years ago)

ES4 had this as "like" (at one point "is like"):

(arg1 like MyClass)

How deep this goes is one design decision; there are lots of others.

Pattern matching is more precise and flexible, and that's why we considered changing destructuring (which uses the pattern subgrammar) to refutable from irrefutable. Even now with destructuring irrefutable, patterns in catch clauses, match statements/expressions, or other future forms would want the same subgrammar, as much as possible -- but with refutability.

Just doing 'like' and calling it a day isn't really enough. We know what it means, right? Like, totally!!! ;-)

slang.soe.ucsc.edu/cormac/papers/valleyscript.pdf

# Rick Waldron (12 years ago)

On Fri, Aug 9, 2013 at 11:52 PM, Brendan Eich <brendan at mozilla.com> wrote:

Rick Waldron wrote:

My argument was specifically about the current meaning of the ascii exclamation "!" and that assigning it an additional context-based meaning that's quite the opposite of the current unary operator meaning,

Ok, and I'm with you (recall Mark M. wants ! as restricted-production binary operator for promises),

Yep, and I've also expressed my concern with that use as well, from yet a different perspective: esdiscuss/2013-June/031374 (note that my point there has no basis in existing JS operator semantics and was completely subjective).

but you still swapped refutable and irrefutable :-P.

Only for the sake of making the grok-ability argument! ;)

isn't a proposal that I would support. This is stated with no regard for

previous refutable matching proposals.

Right, but remember: the kind of destructuring that imputes undefined for missing property is irrefutable. Can't refute so can't mismatch so can't fall thru to later match-case. That's all I wanted to get across ;-).

Of course and I should've addressed that originally so that my points would've been clearer—apologies for the noise caused by not doing so.

# Andreas Rossberg (12 years ago)

On 10 August 2013 22:15, Brendan Eich <brendan at mozilla.com> wrote:

Pattern matching is more precise and flexible, and that's why we considered changing destructuring (which uses the pattern subgrammar) to refutable from irrefutable. Even now with destructuring irrefutable, patterns in catch clauses, match statements/expressions, or other future forms would want the same subgrammar, as much as possible -- but with refutability.

I'm confused now. Was there an actual decision to go back to irrefutable matching? I don't see that in the meeting notes (just an argument that it would be future hostile, which I strongly agree with).

# Allen Wirfs-Brock (12 years ago)

On Aug 12, 2013, at 2:22 AM, Andreas Rossberg wrote:

On 10 August 2013 22:15, Brendan Eich <brendan at mozilla.com> wrote:

Pattern matching is more precise and flexible, and that's why we considered changing destructuring (which uses the pattern subgrammar) to refutable from irrefutable. Even now with destructuring irrefutable, patterns in catch clauses, match statements/expressions, or other future forms would want the same subgrammar, as much as possible -- but with refutability.

I'm confused now. Was there an actual decision to go back to irrefutable matching? I don't see that in the meeting notes (just an argument that it would be future hostile, which I strongly agree with).

As the meeting I reported that I had spend considerable time reviewing the refutable matching strawman. it's unresolved issues, and the likely impart on the specification relative to other high priority work items. My conclusion was that is unlikely we could incorporate that strawman and still meet our year end spec. completion goal. Instead, I proposed we stick with the currently specified destructuring semantics with a couple slight modification that I had previously described in a private email exchange with you (which I've copied below).

The discussion that followed was mostly about future proofing and various people trying to channel for you in that regard. The schedule issue was real and there wasn't any particular push back on that. Based upon that discussion, plan is to update the draft to match what what I described below unless you have similar scale alternatives to suggest.


On Jul 17, 2013, at 3:00 AM, Andreas Rossberg wrote:

The essence of your suggestion is to defer the ? operator, is that correct? I'd be totally fine with that. I'd even be happy to drop it entirely. But keep in mind that we came up with it to make refutable matching acceptable to proponents of sloppy style.

On 17 July 2013 00:50, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

I've been looking at the possibility that that we may have to defer some accepted ES6 proposal if we are going to make our end of year feature complete spec. target.

One of the proposal that is a candidate for deferral is harmony:refutable_matching

This was a late addition. I've already spent significant time on understanding it implications and feel that resolving open design issues and properly integrate it into the spec. is likely to take more time than we can afford right now.

In addition to unresolved syntax and semantic issues mentioned in the Wiki proposal, there are a number of semantic differences between patterns in regular declarations, patterns in parameter lists, and patterns in the LHS of assignment expressions that need to be work through in the spec. I'm also worried that decisions we make here could potentially negatively impact a future pattern switch statement if we don't also take that into account at the same time.

I thinking it may be better to introduce this form of pattern matching (include the switch statement) as a complete unit in ES7 rather than trying to get it into ES6.

However, doing so will requires that the currently spec'ed destructuring be made future proof. I think we can do that with a few simple changes to the current spec:

  1. No implicit conversion, for example the following all throw:
let {a } = undefined;
let [x,...y] = "abc";
(({x})=>x)(0);
let {a: {x}} = {a: false};
  1. unmatched property selectors in patterns throw:
let {a} = {b:5}; //throws
let [a,b,c] = [0,1]; //throws
  1. unless they have a default value provided:
let {a=undefined} = {b:5}; //variable a initialized to undefined
let [a,b,c=2] = [0,1];  // a initialized to 0, b to 1, c to 2

These are simple changes to make to the existing spec. My sense is that they preserve the primary desturcturing use cases (include default value assignment, particularly for parameters) while leaving us positioned to add ? and other extended pattern features in ES6+

What do you think? Would these changes to the existing spec. be enough to future proof destructuring and enable patterns in the next round?

# Andreas Rossberg (12 years ago)

On 12 August 2013 18:52, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

As the meeting I reported that I had spend considerable time reviewing the refutable matching strawman. it's unresolved issues, and the likely impart on the specification relative to other high priority work items. My conclusion was that is unlikely we could incorporate that strawman and still meet our year end spec. completion goal. Instead, I proposed we stick with the currently specified destructuring semantics with a couple slight modification that I had previously described in a private email exchange with you (which I've copied below).

As I said in my reply, I'm totally fine with what you describe in that mail. But correct me if I'm wrong, that is refutable destructuring, isn't it? All you seem to drop is the optional irrefutable part (the '?' feature). That's why I am quite confused about Brendan's statement above.

The discussion that followed was mostly about future proofing and various people trying to channel for you in that regard. The schedule issue was real and there wasn't any particular push back on that. Based upon that discussion, plan is to update the draft to match what what I described below unless you have similar scale alternatives to suggest.

OK, I am happy to hear that the plan is to adopt your suggestion as is (the meeting notes only list point 1, so that wasn't obvious).

# Brendan Eich (12 years ago)

Andreas Rossberg wrote:

As I said in my reply, I'm totally fine with what you describe in that mail. But correct me if I'm wrong, that_is_ refutable destructuring, isn't it? All you seem to drop is the optional irrefutable part (the '?' feature). That's why I am quite confused about Brendan's statement above.

Possibly I missed something (I was at the meeting on the 2nd and 3rd days but not day 1).

Allen, what does your latest draft do on

var {p} = {};

Throw, or bind p to undefined?

# Allen Wirfs-Brock (12 years ago)

throws

to bind to undefined you would say:

var {p=undefined} = {};
# Brendan Eich (12 years ago)

Ok, then!

My apologies, Andreas, I was your champion in reviving refutable patterns for destructuring in ES6. I misheard things while at the meeting.

# Dmitry Soshnikov (12 years ago)

OK, so it's turned out to be refutable nevertheless. It seems everyone was missing this point until this mail on the thread.

From the implementation perspective it's postponed to runtime check with stopping the destrucuring, and just throwing at first mismatch.

Thanks for the I info. It's also probably worth waiting until Sep meeting for possible changes.

# David Herman (12 years ago)

On Aug 14, 2013, at 9:54 AM, Dmitry Soshnikov <dmitry.soshnikov at gmail.com> wrote:

OK, so it's turned out to be refutable nevertheless.

This is not what I remember of the conversation, at all.

My understanding was that pretty much everyone in the room, at least those who participated in the conversation, felt that refutable destructuring was a mistake, but that we couldn't really come to any conclusions without Brendan and Andreas there, since the two of them had championed refutable destructuring.

IOW, we don't have consensus about this issue.

# David Herman (12 years ago)

On Aug 15, 2013, at 9:27 PM, David Herman <dherman at mozilla.com> wrote:

we couldn't really come to any conclusions without Brendan and Andreas there

My mistake, Brendan was there. It was only Andreas who wasn't there.

# Kevin Smith (12 years ago)

My understanding was that pretty much everyone in the room, at least those who participated in the conversation, felt that refutable destructuring was a mistake,

Can you elaborate, please? Why?

# Allen Wirfs-Brock (12 years ago)

On Aug 15, 2013, at 9:27 PM, David Herman wrote:

This is not what I remember of the conversation, at all.

My understanding was that pretty much everyone in the room, at least those who participated in the conversation, felt that refutable destructuring was a mistake, but that we couldn't really come to any conclusions without Brendan and Andreas there, since the two of them had championed refutable destructuring.

IOW, we don't have consensus about this issue.

Personally, I think there is all too much confusion over the words "refutable" and "irrefutable". I don't care about that terminology at all and we shouldn't be reading implications into the use of those terms.

At the meeting we agree to take ? off the table because there are too many open issues and not enough time before the end of the year to address them and still get higher priority things done.

The decisions that need to be made are simply:

  1. Regarding a value that is being destructured: Implicit conversion to object or no implicit conversion, for example the following all throw:
let {a } = undefined;     //throw or interpreted as { }
let [x,...y] = "abc";          //  ToObject("abc")?
(({x})=>x)(0);                 // ToObject(0)?

let {a: {x}} = {a: false}; // ToObject(false) ?

The July meeting notes explicit report consensus that ToObject should not be applied in the above cases.

  1. Do unmatched property selectors in patterns bind to undefined or throw o:
let {a} = {b:5};      //  is a initialized to undefined or does this throws
let [a,b,c] = [0,1]; //  is c initialized to undefined or does this throws

Note that for #2 a default value expression over-rides either alternative

let {a=undefined} = {b:5}; //variable a initialized to undefined
let [a,b,c=2] = [0,1];  // a initialized to 0, b to 1, c to 2

So, the answer to #2 is the only open one.

I think either is a reasonable default behavior for ES. My current draft for 2 says throw on missing property unless a default value is provided. Prior to refutable matching discussions and proposals it said: a missing treated as having the value undefined.

Dave, is throwing on a missing property if it lacks a default value the thing that you consider to be a mistake?

I'm happy to revert #2 back to not throwing, but the spec. must say something for these cases and I don't want to keep changing back and forth. There are various views on regarding which alternative for #2 is more/less future friendly. Personally, I think we still have plenty of future flexibility either way we go.

# Dmitry Soshnikov (12 years ago)

I think the reasoning here should be through trying to predict the most frequent use-cases.

E.g. Erlang which completely based on pattern matching code, throws in this case. But Erlang is a functional with immutable state in its core, so there pattern matching at assignment is exactly the pattern matching (even for simple vars). And destrucuring there is just a consequence of pattern matching.

JS assignment is not a matching by its nature, and here the destrucuring is the main part. Especially if to take into account that for years foo.nonExisting returns undefined here.

It seems to me that not throwing fits better for JS nature.

And for the strict match one could introduce match(...) function which already would throw providing exactly matching procedure first, and then destructuring as a consequence.

# Kevin Smith (12 years ago)

And for the strict match one could introduce match(...) function which already would throw providing exactly matching procedure first, and then destructuring as a consequence.

Do you not think that it would be awkward to have the exact same pattern syntax for these two cases (matching and destructuring), but with different semantics?

# Dmitry Soshnikov (12 years ago)

On Fri, Aug 16, 2013 at 11:26 AM, Kevin Smith <zenparsing at gmail.com> wrote:

Do you not think that it would be awkward to have the exact same pattern syntax for these two cases (matching and destructuring), but with different semantics?

Yes, I don't think so. Also, this exact (or strict, or refutable if you will) matching I'm proposing as addition. And for this it's good to have a very good practical use-case and a reason. Do you know such practical use-cases today when people need strict match with throwing? How widely they are used?

tl;dr:

In immutable state languages, there is no assignment operation, there is only "binding-and-matching" operation. Which means an unbound variable can be bound once, and all other "assignment" operations already pattern matching operations -- they can only check whether the LHS matches to what is on RHS.

X = 10; // initial binding

X = 20; // throw, doesn't match
X = 10; // OK, match

Y = 10;
X = Y; // OK, match

Z = [1, 2, 3];
Z = [1, 2, 3]; // OK, match
[A, B, C] = Z; // OK, match. See -- the matching goes first, and the
destructuring is just a consequence.
[A, _, C] = Z; // OK, match, skipping second element
[A, B] = Z; // throw, doesn't match

In JS, there is mutation and assignment. And pattern matching here is secondary. Initially exactly the destructuring plays main role here. And again, for the current foo.nonExisting being undefined use-case is also leans towards not throwing.

The non-strict destructuring use-case is though can be wide spread, especially with config parameters:

function init({ip, coords: [x, y]}) { ... }

The match function can go either on RHS (which probably better, but I'm not sure at implementation), or LHS:

switch (match(foo)) {
  case {x, y}:
  case [a,b ,c]
}

The match(...) function may just set [[StrictMatch]] temp prop on the object and then matching goes with the strict (I wouldn't do it using "use strict;" though). But don't wanna go deeply to bike-sheading about it.

# Kevin Smith (12 years ago)

Do you not think that it would be awkward to have the exact same pattern syntax for these two cases (matching and destructuring), but with different semantics?

Yes, I don't think so.

Hmmm... Let me rephrase. It would be awkward and confusing to have divergent semantics for the same pattern syntax in destructuring and matching.

: )

# Dmitry Soshnikov (12 years ago)

On Fri, Aug 16, 2013 at 12:38 PM, Kevin Smith <zenparsing at gmail.com> wrote:

Hmmm... Let me rephrase. It would be awkward and confusing to have divergent semantics for the same pattern syntax in destructuring and matching.

This is again if we need strict matching. As long as JS is assignment-base language with mutable state and that foo.nonExisting === undefined today, I think the destructuring w/o throwing should be the main course. And if you want the strict match, it can be an extension. If we need it. If we have use-cases. This match(...) is just an idea, of course it should be worked on.

# Allen Wirfs-Brock (12 years ago)

On Aug 16, 2013, at 12:18 PM, Dmitry Soshnikov wrote:

In JS, there is mutation and assignment. And pattern matching here is secondary. Initially exactly the destructuring plays main role here. And again, for the current foo.nonExisting being undefined use-case is also leans towards not throwing.

In JS we also have binding initialization:

let x; // outer x
{
  //
  //in this zone outer 'x' is shadowed by the uninitialized inner 'x'.  any reference to 'x' will throw
  //
  let x=42;    //initialize the inner 'x' binding to the value 42
  //
  //In this zone a reference to 'x' returns the current value of inner 'x'
  //
}

In ES6 a reference to 'x' is always valid if it is dominated by a single name lexical declaration of 'x'. If we want to preserve this for destructuring initialized bindings we must deal with:

let {x} = {};

More specifically, we don't want to allow control to pas such a declaration without initializing the local binding for 'x'. So our alternatives are initialize 'x' to undefined as if it was a single name binding without an initializer or throwing to stop forward progress.

I think either would be acceptable. However, I think throwing is like to reveal bugs that might otherwise be missed prior to deployment and as a code reader I would prefer to encounter

let {x=undefined) = {};

which communicates much more clearly that there is an expectation that 'x' may not exist as a property of the RHS.

# Brandon Benvie (12 years ago)

On 8/16/2013 12:56 PM, Allen Wirfs-Brock wrote:

However, I think throwing is like to reveal bugs that might otherwise be missed prior to deployment and as a code reader I would prefer to encounter

let {x=undefined) = {};

which communicates much more clearly that there is an expectation that 'x' may not exist as a property of the RHS.

I think this is true of assignment/declaration destructuring, but untrue for parameter destructuring. I think a very common use case for parameter destructuring is optional values in an options object. Given that we want assignment destructuring and parameter destructuring to be the same thing, I think that we have to allow soft-fail.

# Domenic Denicola (12 years ago)

Actually, I think it'd be fantastic to have an easy way to communicate required parameters in an options object. It's a fairly common pattern; for example in the S3 library knox that I maintain we require bucket, key, and secret, but everything else has defaults.

# Brandon Benvie (12 years ago)

On 8/16/2013 2:08 PM, Domenic Denicola wrote:

Actually, I think it'd be fantastic to have an easy way to communicate required parameters in an options object.

I agree and this is why I was a fan of Axel's +/! "this is required" prefix.

One of the reason's JS is so popular is because hard failure is opt-in. That is: by default the language will not punish you for mistakes made as a noob/while developing. You can access a non-existent property, for example, without it destroying the whole program. This is, of course, also a source of subtle and hard to diagnose bugs. But, on balance, I think it's worth it for what JS is meant to do.

That doesn't mean we can't have opt-in strictness, though. This is why I love Axel's proposal: you can opt-in for strictness and get the guarantees you want. This is the same reason TypeScript exists, and has gained such a following. TypeScript is to ECMAScript as refutable destructuring is to Axel's proposal.

# Brendan Eich (12 years ago)

Brandon Benvie wrote:

On 8/16/2013 2:08 PM, Domenic Denicola wrote:

Actually, I think it'd be fantastic to have an easy way to communicate required parameters in an options object.

I agree and this is why I was a fan of Axel's +/! "this is required" prefix.

Having such syntax available would address the required-parameters use-case, but still leave a split between destructuring assignment/binding and any future match syntax that uses patterns too.

One of the reason's JS is so popular is because hard failure is opt-in. That is: by default the language will not punish you for mistakes made as a noob/while developing. You can access a non-existent property, for example, without it destroying the whole program. This is, of course, also a source of subtle and hard to diagnose bugs. But, on balance, I think it's worth it for what JS is meant to do.

Fail-soft in this regard is a crucial feature of the web and its "versioning is an anti-pattern" -- by which I mean object detection.

That doesn't mean we can't have opt-in strictness, though. This is why I love Axel's proposal: you can opt-in for strictness and get the guarantees you want. This is the same reason TypeScript exists, and has gained such a following. TypeScript is to ECMAScript as refutable destructuring is to Axel's proposal.

Again, this works except in a match construct, where failure to trigger next-pattern attempt must be the default.