Proposal: switch expressions

David Koblas david at koblas.com
Tue Feb 26 18:34:17 UTC 2019


Jordan,

Thanks for taking time to read and provide thoughts.

I just back and re-read the pattern matching proposal and it still fails 
on the basic requirement of being an Expression not a Statement.  The 
problem that I see and want to address is the need to have something 
that removes the need to chain trinary expressions together to have an 
Expression.

This is unmaintainable --

     const x = v === 'foo' ? 1 : v === 'bar' ? 3 : v === 'baz' ? 6 : 99;

This is maintainable, but is less than ideal:

    let x;

    switch (v) {
    case "foo":
      x = 1;
      break;
    case "bar":
      x = 3;
      break;
    case "baz":
      x = 6;
      break;
    default:
      x = 99;
      break;
    }

Pattern matching does shorten the code, but you have a weird default 
case and also still end up with a loose variable and since pattern 
matching is a statement you still have a initially undefined variable.

    let x;

    case (v) {
      when "foo" -> x = 1;
      when "bar" -> x = 3;
      when "baz" -> x = 6;
      when v -> x = 99;
    }

Let's try do expressions, I'll leave people's thoughts to themselves.

    const x = do {
      if (v === "foo") { 1; }
      else if (v === "bar") { 3; }
      else if (v === "baz") { 6; }
      else { 99; }
    }

Or as another do expression variant:

    const x = do {
      switch (v) {
        case "foo": 1; break;
        case "bar": 3; break;
        case "baz": 6; break;
        default: 99; break;
      }
    }

And as I'm thinking about switch expressions:

    const x = switch (v) {
      case "foo" => 1;
      case "bar" => 3;
      case "baz" => 6;
      default => 99;
    }

What I really like is that it preserves all of the normal JavaScript 
syntax with the small change that a switch is allowed in an expression 
provided that all of the cases evaluate to expressions hence the use of 
the '=>' as an indicator. Fundamentally this is a very basic concept 
where you have a state machine and need it switch based on the current 
state and evaluate to the new state.

    const nextState = switch (currentState) {
       case ... =>
    }



On 2/25/19 4:00 PM, Jordan Harband wrote:
> Pattern Matching is still at stage 1; so there's not really any 
> permanent decisions that have been made - the repo theoretically 
> should contain rationales for decisions up to this point.
>
> I can speak for myself (as "not a champion" of that proposal, just a 
> fan) that any similarity to the reviled and terrible `switch` is 
> something I'll be pushing back against - I want a replacement that 
> lacks the footguns and pitfalls of `switch`, and that is easily 
> teachable and googleable as a different, distinct thing.
>
> On Mon, Feb 25, 2019 at 12:42 PM David Koblas <david at koblas.com 
> <mailto:david at koblas.com>> wrote:
>
>     Jordan,
>
>     One question that I have lingering from pattern matching is why is
>     the syntax so different?  IMHO it is still a switch statement with
>     a variation of the match on the case rather than a whole new
>     construct.
>
>     Is there somewhere I can find a bit of discussion about the
>     history of the syntax decisions?
>
>     --David
>
>
>     On Feb 25, 2019, at 12:33 PM, Jordan Harband <ljharb at gmail.com
>     <mailto:ljharb at gmail.com>> wrote:
>
>>     Additionally, https://github.com/tc39/proposal-pattern-matching -
>>     switch statements are something I hope we'll soon be able to
>>     relegate to the dustbin of history.
>>
>>     On Mon, Feb 25, 2019 at 6:01 AM David Koblas <david at koblas.com
>>     <mailto:david at koblas.com>> wrote:
>>
>>         I quite aware that it’s covered in do expressions. Personally
>>         I find do expressions non-JavaScript in style and it’s also
>>         not necessarily going to make it into the language.
>>
>>         Hence why I wanted to put out there the idea of switch
>>         expressions.
>>
>>         --David
>>
>>
>>         On Feb 25, 2019, at 5:28 AM, N. Oxer <blueshuk2 at gmail.com
>>         <mailto:blueshuk2 at gmail.com>> wrote:
>>
>>>         Hi,
>>>
>>>         This would be covered by do expressions
>>>         <https://github.com/tc39/proposal-do-expressions>. You could
>>>         just do:
>>>
>>>         ```js
>>>         const category = do {
>>>           switch (...) {
>>>             ...
>>>           };
>>>         };
>>>         ```
>>>
>>>         On Sun, Feb 24, 2019 at 10:42 AM David Koblas
>>>         <david at koblas.com <mailto:david at koblas.com>> wrote:
>>>
>>>             After looking at a bunch of code in our system noted
>>>             that there are many
>>>             cases where our code base has a pattern similar to this:
>>>
>>>                  let category = data.category;
>>>
>>>                  if (category === undefined) {
>>>                    // Even if Tax is not enabled, we have defaults
>>>             for incomeCode
>>>                    switch (session.merchant.settings.tax.incomeCode) {
>>>                      case TaxIncomeCode.RENTS_14:
>>>                        category = PaymentCategory.RENT;
>>>                        break;
>>>                      case TaxIncomeCode.INDEPENDENT_PERSONAL_SERVICE_17:
>>>                        category = PaymentCategory.SERVICES;
>>>                        break;
>>>                      case TaxIncomeCode.INDEPENDENT_PERSONAL_SERVICE_17:
>>>                        category = PaymentCategory.SERVICES;
>>>                        break;
>>>                    }
>>>                  }
>>>
>>>             I also bumped into a block of go code that also
>>>             implemented similar
>>>             patterns, which really demonstrated to me that there
>>>             while you could go
>>>             crazy with triary nesting there should be a better way. 
>>>             Looked at the
>>>             pattern matching proposal and while could possibly help
>>>             looked like it
>>>             was overkill for the typical use case that I'm seeing.
>>>             The most relevant
>>>             example I noted was switch expressions from Java.  When
>>>             applied to this
>>>             problem really create a simple result:
>>>
>>>                  const category = data.category || switch
>>>             (setting.incomeCode) {
>>>                    case TaxIncomeCode.RENTS_14 => PaymentCategory.RENT;
>>>                    case TaxIncomeCode.ROYALTIES_COPYRIGHTS_12 =>
>>>             PaymentCategory.ROYALTIES;
>>>                    case
>>>             TaxIncomeCode.INDEPENDENT_PERSONAL_SERVICE_17 =>
>>>             PaymentCategory.SERVICES;
>>>                    default => PaymentCategory.OTHER;
>>>                  }
>>>
>>>             Note; the instead of using the '->' as Java, continue to
>>>             use => and with
>>>             the understanding that the right hand side is
>>>             fundamentally function.
>>>             So similar things to this are natural, note this
>>>             proposal should remove
>>>             "fall through" breaks and allow for multiple cases as such.
>>>
>>>                  const quarter = switch (foo) {
>>>                    case "Jan", "Feb", "Mar" => "Q1";
>>>                    case "Apr", "May", "Jun" => "Q2";
>>>                    case "Jul", "Aug", "Sep" => "Q3";
>>>                    case "Oct", "Nov", "Dec" => { return "Q4" };
>>>                    default => { throw new Error("Invalid Month") };
>>>                  }
>>>
>>>             Also compared this to the do expression proposal, it
>>>             also provides a
>>>             substantial simplification, but in a way that is more
>>>             consistent with
>>>             the existing language.  In one of their examples they
>>>             provide an example
>>>             of the Redux reducer
>>>             https://redux.js.org/basics/reducers#splitting-reducers
>>>             -- this would be
>>>             a switch expression implementation.
>>>
>>>                  function todoApp(state = initialState, action) =>
>>>             switch
>>>             (action.type) {
>>>                    case SET_VISIBILITY_FILTER => { ...state,
>>>             visibilityFilter:
>>>             action.filter };
>>>                    case ADD_TODO => {
>>>                        ...state, todos: [
>>>                          ...state.todos,
>>>                          {
>>>                            text: action.text,
>>>                            completed: false
>>>                          }
>>>                        ]
>>>                      };
>>>                    case TOGGLE_TODO => {
>>>                        ...state,
>>>                        todos: state.todos.map((todo, index) =>
>>>             (index ===
>>>             action.index) ? { ...todo, completed: !todo.completed }
>>>             : todo)
>>>                      };
>>>                    default => state;
>>>                  }
>>>
>>>
>>>
>>>             _______________________________________________
>>>             es-discuss mailing list
>>>             es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
>>>             https://mail.mozilla.org/listinfo/es-discuss
>>>
>>         _______________________________________________
>>         es-discuss mailing list
>>         es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
>>         https://mail.mozilla.org/listinfo/es-discuss
>>
On 2/25/19 3:42 PM, David Koblas wrote:
> Jordan,
>
> One question that I have lingering from pattern matching is why is the 
> syntax so different?  IMHO it is still a switch statement with a 
> variation of the match on the case rather than a whole new construct.
>
> Is there somewhere I can find a bit of discussion about the history of 
> the syntax decisions?
>
> --David
>
>
> On Feb 25, 2019, at 12:33 PM, Jordan Harband <ljharb at gmail.com 
> <mailto:ljharb at gmail.com>> wrote:
>
>> Additionally, https://github.com/tc39/proposal-pattern-matching - 
>> switch statements are something I hope we'll soon be able to relegate 
>> to the dustbin of history.
>>
>> On Mon, Feb 25, 2019 at 6:01 AM David Koblas <david at koblas.com 
>> <mailto:david at koblas.com>> wrote:
>>
>>     I quite aware that it’s covered in do expressions. Personally I
>>     find do expressions non-JavaScript in style and it’s also not
>>     necessarily going to make it into the language.
>>
>>     Hence why I wanted to put out there the idea of switch expressions.
>>
>>     --David
>>
>>
>>     On Feb 25, 2019, at 5:28 AM, N. Oxer <blueshuk2 at gmail.com
>>     <mailto:blueshuk2 at gmail.com>> wrote:
>>
>>>     Hi,
>>>
>>>     This would be covered by do expressions
>>>     <https://github.com/tc39/proposal-do-expressions>. You could
>>>     just do:
>>>
>>>     ```js
>>>     const category = do {
>>>       switch (...) {
>>>         ...
>>>       };
>>>     };
>>>     ```
>>>
>>>     On Sun, Feb 24, 2019 at 10:42 AM David Koblas <david at koblas.com
>>>     <mailto:david at koblas.com>> wrote:
>>>
>>>         After looking at a bunch of code in our system noted that
>>>         there are many
>>>         cases where our code base has a pattern similar to this:
>>>
>>>              let category = data.category;
>>>
>>>              if (category === undefined) {
>>>                // Even if Tax is not enabled, we have defaults for
>>>         incomeCode
>>>                switch (session.merchant.settings.tax.incomeCode) {
>>>                  case TaxIncomeCode.RENTS_14:
>>>                    category = PaymentCategory.RENT;
>>>                    break;
>>>                  case TaxIncomeCode.INDEPENDENT_PERSONAL_SERVICE_17:
>>>                    category = PaymentCategory.SERVICES;
>>>                    break;
>>>                  case TaxIncomeCode.INDEPENDENT_PERSONAL_SERVICE_17:
>>>                    category = PaymentCategory.SERVICES;
>>>                    break;
>>>                }
>>>              }
>>>
>>>         I also bumped into a block of go code that also implemented
>>>         similar
>>>         patterns, which really demonstrated to me that there while
>>>         you could go
>>>         crazy with triary nesting there should be a better way. 
>>>         Looked at the
>>>         pattern matching proposal and while could possibly help
>>>         looked like it
>>>         was overkill for the typical use case that I'm seeing. The
>>>         most relevant
>>>         example I noted was switch expressions from Java.  When
>>>         applied to this
>>>         problem really create a simple result:
>>>
>>>              const category = data.category || switch
>>>         (setting.incomeCode) {
>>>                case TaxIncomeCode.RENTS_14 => PaymentCategory.RENT;
>>>                case TaxIncomeCode.ROYALTIES_COPYRIGHTS_12 =>
>>>         PaymentCategory.ROYALTIES;
>>>                case TaxIncomeCode.INDEPENDENT_PERSONAL_SERVICE_17 =>
>>>         PaymentCategory.SERVICES;
>>>                default => PaymentCategory.OTHER;
>>>              }
>>>
>>>         Note; the instead of using the '->' as Java, continue to use
>>>         => and with
>>>         the understanding that the right hand side is fundamentally
>>>         function.
>>>         So similar things to this are natural, note this proposal
>>>         should remove
>>>         "fall through" breaks and allow for multiple cases as such.
>>>
>>>              const quarter = switch (foo) {
>>>                case "Jan", "Feb", "Mar" => "Q1";
>>>                case "Apr", "May", "Jun" => "Q2";
>>>                case "Jul", "Aug", "Sep" => "Q3";
>>>                case "Oct", "Nov", "Dec" => { return "Q4" };
>>>                default => { throw new Error("Invalid Month") };
>>>              }
>>>
>>>         Also compared this to the do expression proposal, it also
>>>         provides a
>>>         substantial simplification, but in a way that is more
>>>         consistent with
>>>         the existing language.  In one of their examples they
>>>         provide an example
>>>         of the Redux reducer
>>>         https://redux.js.org/basics/reducers#splitting-reducers --
>>>         this would be
>>>         a switch expression implementation.
>>>
>>>              function todoApp(state = initialState, action) => switch
>>>         (action.type) {
>>>                case SET_VISIBILITY_FILTER => { ...state,
>>>         visibilityFilter:
>>>         action.filter };
>>>                case ADD_TODO => {
>>>                    ...state, todos: [
>>>                      ...state.todos,
>>>                      {
>>>                        text: action.text,
>>>                        completed: false
>>>                      }
>>>                    ]
>>>                  };
>>>                case TOGGLE_TODO => {
>>>                    ...state,
>>>                    todos: state.todos.map((todo, index) => (index ===
>>>         action.index) ? { ...todo, completed: !todo.completed } : todo)
>>>                  };
>>>                default => state;
>>>              }
>>>
>>>
>>>
>>>         _______________________________________________
>>>         es-discuss mailing list
>>>         es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
>>>         https://mail.mozilla.org/listinfo/es-discuss
>>>
>>     _______________________________________________
>>     es-discuss mailing list
>>     es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
>>     https://mail.mozilla.org/listinfo/es-discuss
>>
>
> _______________________________________________
> 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/20190226/89412436/attachment-0001.html>


More information about the es-discuss mailing list