Proposal-pattern-matching: The possibility of underscores as else legs would conflict with identifier patterns

Created on 17 Jan 2018  路  5Comments  路  Source: tc39/proposal-pattern-matching

The proposal currently holds open the possibility to use an underscore instead of else:

I've gone with else as it aligns with other areas of JavaScript, but you might prefer something more terse like _ (especially if you're used to F#). _ also has the advantage of binding a value enabling you to reference a value in a guaranteed non-sideeffecty way.

This would be problematic because the proposal allows arbitrary identifiers in the same place but with other meaning:

Identifiers are looked up for their runtime value. A value matches if it has a Symbol.matches method which returns something truthy when passed the value being matched (see also optional extensions below for a way to destructure the value returned from the Symbol.matches method).

Since underscores are valid identifier as well this leads to a number of ambiguities:

const _ = 'foo'
match ('bar') {
  // ...
  _:  // match or not?
}

The value of _ doesn't equal the string bar but underscore also is the default case.

function Foo() {}
function Bar() {}
function _ () {}

const myVar = new Foo()
match (myVar) {
  Bar: {},
  _: {}, // match or not?
}

myVar is not instanceOf _ but underscore also is the default case.

function _ () {}

const myVar = new _();
match (myVar) {
  // ...
  _:  _ // log myVar or the function above?
}

If in this case underscore is considered the default case, _ would be assigned to the matched value (myVar). If it is understood as normal look up of the value and Symbol.matches checks with instanceOf, _ should still be a reference to the function above.

Underscores are also commonly used as a normal variable and assigning _ to the matched value would prevent accessing it:

const _ require('lodash')
const foo = 'bar'
match(foo) {
    _: _.startCase(foo)
}

Accessing startCase from lodash wouldn't be possible since _ would be assigned to the string foo.

I would suggest dismissing the possibility due to too many ambiguities.

Most helpful comment

The _ case would be primary used for a 'default' case, so why not use the existing else keyword for this defined by the proposal? ... might work as a placeholder (or indeed _). Languages like Elixir solve this problem by requiring explicit demarcations when you are comparing against an existing value.

My proposals:

````js
const foo = match(foo) {
else: foo
}

// ... is already the spread operator so I think this makes sense
const foo = match(foo) {
...: defaultCaseExpression // matches anything. Might cause confusion with [...] at a glance
}

// I personally think denoting comparisons with existing fields using a caret is more intuitive to someone who is used to this syntax, but it might be more confusing to beginners

import _ from 'lodash';

function isLodash(anything) {
return match (anything) {
^_: true,
_: false
}
}
````

My personal preference would be the caret and _ as a placeholder rather than else.

All 5 comments

The _ case would be primary used for a 'default' case, so why not use the existing else keyword for this defined by the proposal? ... might work as a placeholder (or indeed _). Languages like Elixir solve this problem by requiring explicit demarcations when you are comparing against an existing value.

My proposals:

````js
const foo = match(foo) {
else: foo
}

// ... is already the spread operator so I think this makes sense
const foo = match(foo) {
...: defaultCaseExpression // matches anything. Might cause confusion with [...] at a glance
}

// I personally think denoting comparisons with existing fields using a caret is more intuitive to someone who is used to this syntax, but it might be more confusing to beginners

import _ from 'lodash';

function isLodash(anything) {
return match (anything) {
^_: true,
_: false
}
}
````

My personal preference would be the caret and _ as a placeholder rather than else.

@danpantry

why not use the existing else keyword for this defined by the proposal?

I'm all for using the else keyword for this. Just wanted to point out the _ will not work and can be dismissed.

I personally think denoting comparisons with existing fields using a caret is more intuitive to someone who is used to this syntax, but it might be more confusing to beginners

Note that this would mean that every Identifier Patterns wound need to be prefixed with ^. Array, Date, myRegex or what ever are identifiers just like _. I don't think this is a very elegant solution.

In a regex character class, ^ means "not" - so I don't think that would be a good choice for matching.

@MoritzKn

Note that this would mean that every Identifier Patterns wound need to be prefixed with ^. Array, Date, myRegex or what ever are identifiers just like _. I don't think this is a very elegant solution.

I hadn't seen this section of the proposal and I don't personally agree with it because it causes these complications (but maybe I am just in love with Elixir too much?).

@ljharb

In a regex character class, ^ means "not" - so I don't think that would be a good choice for matching.

Plenty of languages with pattern matching support regular expressions. They do something like this instead of the proposed syntax:

js match (...) { /regexExpression/.test(value) -> doSomething(value) }

Though I think this might be too broad-reaching a criticism of the spec for this issue

Hey y'all! #65 has gotten merged, and a lot of issues have become irrelevant or significantly changed in context. Because of the magnitude of changes and subtle differences in things that seem similar, we've decided to just nuke all existing issues so we can start fresh. Thank you so much for the contributions and discussions and feel free to create new issues if something seems to still be relevant, and link to the original, related issue so we can have a paper trail (but have the benefit of that clean slate anyway).

Specific to this issue: I believe this is no longer a concern, since variables are irrefutable patterns that always assign, rather than match-or-assign, in the new spec, so I think this is resolved.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

xtuc picture xtuc  路  4Comments

chriskuech picture chriskuech  路  8Comments

Haroenv picture Haroenv  路  6Comments

robertkowalski picture robertkowalski  路  4Comments

JLHwung picture JLHwung  路  3Comments