Proposal: switch expressions

Naveen Chawla naveen.chwl at gmail.com
Sat Mar 2 08:43:26 UTC 2019


I don't think those benchmarks test exactly what we are talking about. They
have a dictionary/array look up followed by method dispatch, vs switch case
and execute. Removing the look up it would be: `x.doStuff()` vs
`switch(x.type)...`. Make sense? Don't have time to do it right now.

Logically I think the JS engine can make them perform identically, so even
if benchmarks show something today, I would not be concerned for the future
and so would prefer to opt for the paradigm that offers the best
manageability, which I think is inheritance by a significant margin, in the
cases mentioned. Other types of cases could of course be a whole different
story.

On Sat, 2 Mar 2019, 5:24 am Isiah Meadows, <isiahmeadows at gmail.com> wrote:

> > It would be unthinkable for it to use pattern matching or explicit code
> branchinI'm g instead of method inheritance for type disambiguation during
> render
>
> But it frequently does internally. For example:
>
> - Calculating object projections:
>
> https://github.com/mrdoob/three.js/blob/dev/src/renderers/WebGLRenderer.js#L1243-L1351
> - Rendering object *lists*:
>
> https://github.com/mrdoob/three.js/blob/dev/src/renderers/WebGLRenderer.js#L1353-L1411
> - Setting the rendering mode and controlling basic rendering:
>
> https://github.com/mrdoob/three.js/blob/dev/src/renderers/WebGLRenderer.js#L802-L874
>
> Obviously, it exposes a data-oriented, object oriented API. And it
> does appear it's not *exclusively* conditionals:
>
> - It invokes an dynamic `render` method for "immediate render
> objects":
> https://github.com/mrdoob/three.js/blob/dev/src/renderers/WebGLRenderer.js#L636-L644
> - In `renderBufferDirect`, it does virtual method dispatch on `render`
> based on one of two possible types, but it otherwise uses conditionals
> for everything:\*
>
> https://github.com/mrdoob/three.js/blob/dev/src/renderers/WebGLRenderer.js#L707-L876
> - It uses a fair bit of functional programming in `compile`:
>
> https://github.com/mrdoob/three.js/blob/dev/src/renderers/WebGLRenderer.js#L1009-L1054
>
> However, I'm finding exceptions in its core and renderers, and it
> doesn't appear virtual dispatch is *that* broadly and pervasively
> used, even though it uses methods a lot.
>
> \* This seems like overkill when the diff between the two renderers in
> question [1] [2] consist of an extra method + 2 extra variables [3]
> [4], a few changed method invocations [5] [6], and the rest just due
> to a different name and a useless `var`.
>
> [1]:
> https://github.com/mrdoob/three.js/blob/dev/src/renderers/webgl/WebGLBufferRenderer.js
> [2]:
> https://github.com/mrdoob/three.js/blob/dev/src/renderers/webgl/WebGLIndexedBufferRenderer.js
> [3]:
> https://github.com/mrdoob/three.js/blob/dev/src/renderers/webgl/WebGLIndexedBufferRenderer.js#L15-L22
> [4]:
> https://github.com/mrdoob/three.js/blob/dev/src/renderers/webgl/WebGLIndexedBufferRenderer.js#L61
> [5]:
> https://github.com/mrdoob/three.js/blob/dev/src/renderers/webgl/WebGLIndexedBufferRenderer.js#L26
> [6]:
> https://github.com/mrdoob/three.js/blob/dev/src/renderers/webgl/WebGLIndexedBufferRenderer.js#L53
>
> > I'm curious where you got the idea that method invocation is "far"
> slower than explicit code branching?
>
> - In C++: https://stackoverflow.com/a/8866789
> - JS benchmark with 4 variants (typed method dispatch is polymorphic):
> http://jsben.ch/fbJQH
> - JS benchmark with 12 variants (typed method dispatch is
> megamorphic): http://jsben.ch/aWNDN
>
> And in my experience, the speed difference in real-world
> performance-critical code is not unlike that microbenchmark and is
> sometimes even more drastic, especially if it's a linked list instead
> of just a simple array lookup.
>
> I'd like to emphasize I'm specifically referring to the case where the
> engine can't reliably assume a single method receiver, i.e. when it
> *has* to fall back to dynamic dispatch.
>
> -----
>
> Isiah Meadows
> contact at isiahmeadows.com
> www.isiahmeadows.com
>
> On Fri, Mar 1, 2019 at 6:25 AM Naveen Chawla <naveen.chwl at gmail.com>
> wrote:
> >
> > The entire renderers, cameras, meshes etc. hierarchy uses method
> inheritance and many of those methods are called during scene rendering
> (which is performance sensitive as it happens per frame). It would be
> unthinkable for it to use pattern matching or explicit code branching
> instead of method inheritance for type disambiguation during render,
> because it would explode the code as well as making it error prone due to
> initial cases potentially unintentionally swallowing up cases intended for
> later code branches (or unintentionally repeating code branches if the
> pattern-matching proposal doesn't have "else" behaviour, of which I'm not
> sure, but it if does, it suffers from the first problem anyway).
> >
> > I'm curious where you got the idea that method invocation is "far"
> slower than explicit code branching?
> >
> > On Thu, 28 Feb 2019 at 18:49 Isiah Meadows <isiahmeadows at gmail.com>
> wrote:
> >>
> >> I'm looking at Three.js's code base, and I'm not seeing any method
> >> overriding or abstract methods used except at the API level for
> >> cloning and copying. Instead, you update properties on the supertype.
> >> As far as I can tell, the entirety of Three.js could almost be
> >> mechanically refactored in terms of components instead of inheritance,
> >> without substantially modifying the API apart from a few extra
> >> `.geometry`/etc. property accesses when calling supertype methods.
> >> It's data-driven and almost ECS. (It uses `.isObject3D`,
> >> `.isPerspectiveCamera`, and similar brand checks, but those don't
> >> *need* to be inherited to work.)
> >>
> >> -----
> >>
> >> Isiah Meadows
> >> contact at isiahmeadows.com
> >> www.isiahmeadows.com
> >>
> >> On Thu, Feb 28, 2019 at 12:40 PM Naveen Chawla <naveen.chwl at gmail.com>
> wrote:
> >> >
> >> > I'm not sure that pattern matching handles deep levels of inheritance
> more elegantly than inheritance itself.
> >> >
> >> > If there is a conceptual type hierarchy, then the ability to call
> "super", combine it with specialized functionality, etc. is a lot more
> manageable using localized, separated logic where you don't feel forced to
> read "other patterns" to understand whether your target functionality will
> resolve correctly. And hence, a lower chance of bugs.
> >> >
> >> > As for performance, I'd have to see modern benchmarks. But it's not
> necessarily clear that pattern matching will be particularly fast either.
> I've done game programming with method overriding (Three.js uses it too
> throughout) and there is no notable performance hit from doing so. So I'm
> not clear where you have got this information from.
> >> >
> >> > On Thu, 28 Feb 2019 at 17:06 Isiah Meadows <isiahmeadows at gmail.com>
> wrote:
> >> >>
> >> >> > Using a "switch" here forces you to group classes of objects
> together and then you don't get the 2nd, 3rd, 4th etc. levels of
> specialization that you might later want.
> >> >>
> >> >> Sometimes, this is actually *desired*, and most cases where I
> could've
> >> >> used this, inheritance was not involved *anywhere*. Also, in
> >> >> performance-sensitive contexts (like games, which *heavily* use
> >> >> `switch`/`case`), method dispatch is *far* slower than a simple
> >> >> `switch` statement, so that pattern doesn't apply everywhere.
> >> >>
> >> >> BTW, I prefer https://github.com/tc39/proposal-pattern-matching/
> over
> >> >> this anyways - it covers more use cases and is all around more
> >> >> flexible, so I get more bang for the buck.
> >> >>
> >> >> -----
> >> >>
> >> >> Isiah Meadows
> >> >> contact at isiahmeadows.com
> >> >> www.isiahmeadows.com
> >> >>
> >> >> On Thu, Feb 28, 2019 at 9:23 AM Naveen Chawla <naveen.chwl at gmail.com>
> wrote:
> >> >> >
> >> >> > Hi David!
> >> >> >
> >> >> > Your last example would, I think, be better served by classes and
> inheritance, than switch.
> >> >> >
> >> >> > Dogs are house animals which are animals
> >> >> > Cheetas are wild cats which are animals
> >> >> >
> >> >> > Each could have overridden methods, entirely optionally, where the
> method gets called and resolves appropriately.
> >> >> >
> >> >> > The input argument could be the class name, from which it is
> trivial to instantiate a new instance and get required results.
> >> >> >
> >> >> > Using a "switch" here forces you to group classes of objects
> together and then you don't get the 2nd, 3rd, 4th etc. levels of
> specialization that you might later want.
> >> >> >
> >> >> > All thoughts on this are welcome. Do let me know
> >> >> >
> >> >> > On Thu, 28 Feb 2019 at 14:06 David Koblas <david at koblas.com>
> wrote:
> >> >> >>
> >> >> >> Naveen,
> >> >> >>
> >> >> >> Thanks for your observation.  The example that I gave might have
> been too simplistic, here's a more complete example:
> >> >> >>
> >> >> >> ```
> >> >> >>
> >> >> >>     switch (animal) {
> >> >> >>     case Animal.DOG, Animal.CAT => {
> >> >> >>         // larger block expression
> >> >> >>         // which spans multiple lines
> >> >> >>
> >> >> >>         return "dry food";
> >> >> >>       }
> >> >> >>     case Animal.TIGER, Animal.LION, Animal.CHEETA => {
> >> >> >>         // larger block expression
> >> >> >>         // which spans multiple lines
> >> >> >>
> >> >> >>         return "fresh meat";
> >> >> >>       }
> >> >> >>     case Animal.ELEPHANT => "hay";
> >> >> >>     default => { throw new Error("Unsupported Animal"); };
> >> >> >>     }
> >> >> >>
> >> >> >> ```
> >> >> >>
> >> >> >> While you give examples that would totally work.  Things that
> bother me about the approach are, when taken to something more complex than
> a quick value for value switch you end up with something that looks like
> this.
> >> >> >>
> >> >> >> ```
> >> >> >>
> >> >> >>     function houseAnimal() {
> >> >> >>
> >> >> >>         // larger block expression
> >> >> >>         // which spans multiple lines
> >> >> >>
> >> >> >>         return "dry food";
> >> >> >>     }
> >> >> >>
> >> >> >>     function wildCatFood() {
> >> >> >>
> >> >> >>       // larger block expression
> >> >> >>       // which spans multiple lines
> >> >> >>
> >> >> >>       return "fresh meat";
> >> >> >>     }
> >> >> >>
> >> >> >>
> >> >> >>     const cases = {
> >> >> >>       [Animal.DOG]: houseAnimal,
> >> >> >>       [Animal.CAT]: houseAnimal,
> >> >> >>       [Animal.LION]: wildCatFood,
> >> >> >>       [Animal.TIGER]: wildCatFood,
> >> >> >>       [Animal.CHEETA]: wildCatFood,
> >> >> >>     }
> >> >> >>
> >> >> >>     const food = cases[animal] ? cases[animal]() : (() => {throw
> new Error("Unsuppored Animal")})();
> >> >> >>
> >> >> >> ```
> >> >> >>
> >> >> >> As we all know once any language reaches a basic level of
> functionality anything is possible.  What I think is that JavaScript would
> benefit by having a cleaner approach.
> >> >> >>
> >> >> >> On 2/28/19 4:37 AM, Naveen Chawla wrote:
> >> >> >>
> >> >> >> Isn't the best existing pattern an object literal?
> >> >> >>
> >> >> >> const
> >> >> >>     cases =
> >> >> >>         {
> >> >> >>              foo: ()=>1,
> >> >> >>              bar: ()=>3,
> >> >> >>              baz: ()=>6
> >> >> >>         }
> >> >> >>     ,
> >> >> >>     x =
> >> >> >>         cases[v] ?
> >> >> >>             cases[v]() :
> >> >> >>             99
> >> >> >> ;
> >> >> >>
> >> >> >> What does any proposal have that is better than this? With
> optional chaining feature:
> >> >> >>
> >> >> >> const
> >> >> >>     x =
> >> >> >>         {
> >> >> >>              foo: ()=>1,
> >> >> >>              bar: ()=>3,
> >> >> >>              baz: ()=>6
> >> >> >>         }[v]?.()
> >> >> >>         ||
> >> >> >>         99
> >> >> >> ;
> >> >> >>
> >> >> >> Do let me know your thoughts guys
> >> >> >>
> >> >> >>
> >> >> >> On Thu, 28 Feb 2019 at 06:04 kai zhu <kaizhu256 at gmail.com> wrote:
> >> >> >>>
> >> >> >>> This is unmaintainable --
> >> >> >>>
> >> >> >>>     const x = v === 'foo' ? 1 : v === 'bar' ? 3 : v === 'baz' ?
> 6 : 99;
> >> >> >>>
> >> >> >>> i feel proposed switch-expressions are no more
> readable/maintainable than ternary-operators, if you follow jslint's
> style-guide.  i'll like to see more convincing evidence/use-case that they
> are better:
> >> >> >>>
> >> >> >>> ```javascript
> >> >> >>> /*jslint*/
> >> >> >>> "use strict";
> >> >> >>> const v = "foo";
> >> >> >>> const x = (
> >> >> >>>     v === "foo"
> >> >> >>>     ? 1
> >> >> >>>     : v === "bar"
> >> >> >>>     ? 3
> >> >> >>>     : v === "baz"
> >> >> >>>     ? 6
> >> >> >>>     : 99
> >> >> >>> );
> >> >> >>> ```
> >> >> >>>
> >> >> >>> here's another example from real-world production-code, where
> switch-expressions probably wouldn't help:
> >> >> >>>
> >> >> >>> ```javascript
> >> >> >>> $ node -e '
> >> >> >>> /*jslint devel*/
> >> >> >>> "use strict";
> >> >> >>> function renderRecent(date) {
> >> >> >>> /*
> >> >> >>>  * this function will render <date> to "xxx ago"
> >> >> >>>  */
> >> >> >>>     date = Math.ceil((Date.now() - new Date(date).getTime()) *
> 0.0001) * 10;
> >> >> >>>     return (
> >> >> >>>         !Number.isFinite(date)
> >> >> >>>         ? ""
> >> >> >>>         : date < 60
> >> >> >>>         ? date + " sec ago"
> >> >> >>>         : date < 3600
> >> >> >>>         ? Math.round(date / 60) + " min ago"
> >> >> >>>         : date < 86400
> >> >> >>>         ? Math.round(date / 3600) + " hr ago"
> >> >> >>>         : date < 129600
> >> >> >>>         ? "1 day ago"
> >> >> >>>         : Math.round(date / 86400) + " days ago"
> >> >> >>>     );
> >> >> >>> }
> >> >> >>>
> >> >> >>> console.log(renderRecent(new Date().toISOString())); // "0 sec
> ago"
> >> >> >>> console.log(renderRecent("2019-02-28T05:32:00Z")); // "10 sec
> ago"
> >> >> >>> console.log(renderRecent("2019-02-28T05:27:30Z")); // "5 min ago"
> >> >> >>> console.log(renderRecent("2019-02-28T05:14:00Z")); // "18 min
> ago"
> >> >> >>> console.log(renderRecent("2019-02-28T03:27:00Z")); // "2 hr ago"
> >> >> >>> console.log(renderRecent("2019-02-12T05:27:00Z")); // "16 days
> ago"
> >> >> >>> console.log(renderRecent("2018-02-28T05:27:00Z")); // "365 days
> ago"
> >> >> >>> '
> >> >> >>>
> >> >> >>> 0 sec ago
> >> >> >>> 10 sec ago
> >> >> >>> 5 min ago
> >> >> >>> 18 min ago
> >> >> >>> 2 hr ago
> >> >> >>> 16 days ago
> >> >> >>> 365 days ago
> >> >> >>>
> >> >> >>> $
> >> >> >>> ```
> >> >> >>>
> >> >> >>> On 27 Feb 2019, at 13:12, David Koblas <david at koblas.com> wrote:
> >> >> >>>
> >> >> >>> Just for folks who might be interested, added a babel-plugin to
> see what was involved in making this possible.
> >> >> >>>
> >> >> >>> Pull request available here --
> https://github.com/babel/babel/pull/9604
> >> >> >>>
> >> >> >>> I'm sure I'm missing a bunch of details, but would be interested
> in some help in making this a bit more real.
> >> >> >>>
> >> >> >>> Thanks
> >> >> >>>
> >> >> >>> On 2/26/19 2:40 PM, Isiah Meadows wrote:
> >> >> >>>
> >> >> >>> You're not alone in wanting pattern matching to be
> expression-based:
> >> >> >>>
> >> >> >>> https://github.com/tc39/proposal-pattern-matching/issues/116
> >> >> >>>
> >> >> >>> -----
> >> >> >>>
> >> >> >>> Isiah Meadows
> >> >> >>> contact at isiahmeadows.com
> >> >> >>> www.isiahmeadows.com
> >> >> >>>
> >> >> >>> -----
> >> >> >>>
> >> >> >>> Isiah Meadows
> >> >> >>> contact at isiahmeadows.com
> >> >> >>> www.isiahmeadows.com
> >> >> >>>
> >> >> >>>
> >> >> >>> On Tue, Feb 26, 2019 at 1:34 PM David Koblas <david at koblas.com>
> wrote:
> >> >> >>>
> >> >> >>> 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>
> 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>
> 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>
> 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>
> wrote:
> >> >> >>>
> >> >> >>> Hi,
> >> >> >>>
> >> >> >>> This would be covered by 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>
> 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
> >> >> >>> https://mail.mozilla.org/listinfo/es-discuss
> >> >> >>>
> >> >> >>> _______________________________________________
> >> >> >>> es-discuss mailing list
> >> >> >>> 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>
> 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>
> 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>
> wrote:
> >> >> >>>
> >> >> >>> Hi,
> >> >> >>>
> >> >> >>> This would be covered by 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>
> 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
> >> >> >>> https://mail.mozilla.org/listinfo/es-discuss
> >> >> >>>
> >> >> >>> _______________________________________________
> >> >> >>> es-discuss mailing list
> >> >> >>> 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
> >> >> >>>
> >> >> >>> _______________________________________________
> >> >> >>> es-discuss mailing list
> >> >> >>> 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
> >> >> >>>
> >> >> >>>
> >> >> >>> _______________________________________________
> >> >> >>> es-discuss mailing list
> >> >> >>> 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
>
> On Fri, Mar 1, 2019 at 6:25 AM Naveen Chawla <naveen.chwl at gmail.com>
> wrote:
> >
> > The entire renderers, cameras, meshes etc. hierarchy uses method
> inheritance and many of those methods are called during scene rendering
> (which is performance sensitive as it happens per frame). It would be
> unthinkable for it to use pattern matching or explicit code branching
> instead of method inheritance for type disambiguation during render,
> because it would explode the code as well as making it error prone due to
> initial cases potentially unintentionally swallowing up cases intended for
> later code branches (or unintentionally repeating code branches if the
> pattern-matching proposal doesn't have "else" behaviour, of which I'm not
> sure, but it if does, it suffers from the first problem anyway).
> >
> > I'm curious where you got the idea that method invocation is "far"
> slower than explicit code branching?
> >
> > On Thu, 28 Feb 2019 at 18:49 Isiah Meadows <isiahmeadows at gmail.com>
> wrote:
> >>
> >> I'm looking at Three.js's code base, and I'm not seeing any method
> >> overriding or abstract methods used except at the API level for
> >> cloning and copying. Instead, you update properties on the supertype.
> >> As far as I can tell, the entirety of Three.js could almost be
> >> mechanically refactored in terms of components instead of inheritance,
> >> without substantially modifying the API apart from a few extra
> >> `.geometry`/etc. property accesses when calling supertype methods.
> >> It's data-driven and almost ECS. (It uses `.isObject3D`,
> >> `.isPerspectiveCamera`, and similar brand checks, but those don't
> >> *need* to be inherited to work.)
> >>
> >> -----
> >>
> >> Isiah Meadows
> >> contact at isiahmeadows.com
> >> www.isiahmeadows.com
> >>
> >> On Thu, Feb 28, 2019 at 12:40 PM Naveen Chawla <naveen.chwl at gmail.com>
> wrote:
> >> >
> >> > I'm not sure that pattern matching handles deep levels of inheritance
> more elegantly than inheritance itself.
> >> >
> >> > If there is a conceptual type hierarchy, then the ability to call
> "super", combine it with specialized functionality, etc. is a lot more
> manageable using localized, separated logic where you don't feel forced to
> read "other patterns" to understand whether your target functionality will
> resolve correctly. And hence, a lower chance of bugs.
> >> >
> >> > As for performance, I'd have to see modern benchmarks. But it's not
> necessarily clear that pattern matching will be particularly fast either.
> I've done game programming with method overriding (Three.js uses it too
> throughout) and there is no notable performance hit from doing so. So I'm
> not clear where you have got this information from.
> >> >
> >> > On Thu, 28 Feb 2019 at 17:06 Isiah Meadows <isiahmeadows at gmail.com>
> wrote:
> >> >>
> >> >> > Using a "switch" here forces you to group classes of objects
> together and then you don't get the 2nd, 3rd, 4th etc. levels of
> specialization that you might later want.
> >> >>
> >> >> Sometimes, this is actually *desired*, and most cases where I
> could've
> >> >> used this, inheritance was not involved *anywhere*. Also, in
> >> >> performance-sensitive contexts (like games, which *heavily* use
> >> >> `switch`/`case`), method dispatch is *far* slower than a simple
> >> >> `switch` statement, so that pattern doesn't apply everywhere.
> >> >>
> >> >> BTW, I prefer https://github.com/tc39/proposal-pattern-matching/
> over
> >> >> this anyways - it covers more use cases and is all around more
> >> >> flexible, so I get more bang for the buck.
> >> >>
> >> >> -----
> >> >>
> >> >> Isiah Meadows
> >> >> contact at isiahmeadows.com
> >> >> www.isiahmeadows.com
> >> >>
> >> >> On Thu, Feb 28, 2019 at 9:23 AM Naveen Chawla <naveen.chwl at gmail.com>
> wrote:
> >> >> >
> >> >> > Hi David!
> >> >> >
> >> >> > Your last example would, I think, be better served by classes and
> inheritance, than switch.
> >> >> >
> >> >> > Dogs are house animals which are animals
> >> >> > Cheetas are wild cats which are animals
> >> >> >
> >> >> > Each could have overridden methods, entirely optionally, where the
> method gets called and resolves appropriately.
> >> >> >
> >> >> > The input argument could be the class name, from which it is
> trivial to instantiate a new instance and get required results.
> >> >> >
> >> >> > Using a "switch" here forces you to group classes of objects
> together and then you don't get the 2nd, 3rd, 4th etc. levels of
> specialization that you might later want.
> >> >> >
> >> >> > All thoughts on this are welcome. Do let me know
> >> >> >
> >> >> > On Thu, 28 Feb 2019 at 14:06 David Koblas <david at koblas.com>
> wrote:
> >> >> >>
> >> >> >> Naveen,
> >> >> >>
> >> >> >> Thanks for your observation.  The example that I gave might have
> been too simplistic, here's a more complete example:
> >> >> >>
> >> >> >> ```
> >> >> >>
> >> >> >>     switch (animal) {
> >> >> >>     case Animal.DOG, Animal.CAT => {
> >> >> >>         // larger block expression
> >> >> >>         // which spans multiple lines
> >> >> >>
> >> >> >>         return "dry food";
> >> >> >>       }
> >> >> >>     case Animal.TIGER, Animal.LION, Animal.CHEETA => {
> >> >> >>         // larger block expression
> >> >> >>         // which spans multiple lines
> >> >> >>
> >> >> >>         return "fresh meat";
> >> >> >>       }
> >> >> >>     case Animal.ELEPHANT => "hay";
> >> >> >>     default => { throw new Error("Unsupported Animal"); };
> >> >> >>     }
> >> >> >>
> >> >> >> ```
> >> >> >>
> >> >> >> While you give examples that would totally work.  Things that
> bother me about the approach are, when taken to something more complex than
> a quick value for value switch you end up with something that looks like
> this.
> >> >> >>
> >> >> >> ```
> >> >> >>
> >> >> >>     function houseAnimal() {
> >> >> >>
> >> >> >>         // larger block expression
> >> >> >>         // which spans multiple lines
> >> >> >>
> >> >> >>         return "dry food";
> >> >> >>     }
> >> >> >>
> >> >> >>     function wildCatFood() {
> >> >> >>
> >> >> >>       // larger block expression
> >> >> >>       // which spans multiple lines
> >> >> >>
> >> >> >>       return "fresh meat";
> >> >> >>     }
> >> >> >>
> >> >> >>
> >> >> >>     const cases = {
> >> >> >>       [Animal.DOG]: houseAnimal,
> >> >> >>       [Animal.CAT]: houseAnimal,
> >> >> >>       [Animal.LION]: wildCatFood,
> >> >> >>       [Animal.TIGER]: wildCatFood,
> >> >> >>       [Animal.CHEETA]: wildCatFood,
> >> >> >>     }
> >> >> >>
> >> >> >>     const food = cases[animal] ? cases[animal]() : (() => {throw
> new Error("Unsuppored Animal")})();
> >> >> >>
> >> >> >> ```
> >> >> >>
> >> >> >> As we all know once any language reaches a basic level of
> functionality anything is possible.  What I think is that JavaScript would
> benefit by having a cleaner approach.
> >> >> >>
> >> >> >> On 2/28/19 4:37 AM, Naveen Chawla wrote:
> >> >> >>
> >> >> >> Isn't the best existing pattern an object literal?
> >> >> >>
> >> >> >> const
> >> >> >>     cases =
> >> >> >>         {
> >> >> >>              foo: ()=>1,
> >> >> >>              bar: ()=>3,
> >> >> >>              baz: ()=>6
> >> >> >>         }
> >> >> >>     ,
> >> >> >>     x =
> >> >> >>         cases[v] ?
> >> >> >>             cases[v]() :
> >> >> >>             99
> >> >> >> ;
> >> >> >>
> >> >> >> What does any proposal have that is better than this? With
> optional chaining feature:
> >> >> >>
> >> >> >> const
> >> >> >>     x =
> >> >> >>         {
> >> >> >>              foo: ()=>1,
> >> >> >>              bar: ()=>3,
> >> >> >>              baz: ()=>6
> >> >> >>         }[v]?.()
> >> >> >>         ||
> >> >> >>         99
> >> >> >> ;
> >> >> >>
> >> >> >> Do let me know your thoughts guys
> >> >> >>
> >> >> >>
> >> >> >> On Thu, 28 Feb 2019 at 06:04 kai zhu <kaizhu256 at gmail.com> wrote:
> >> >> >>>
> >> >> >>> This is unmaintainable --
> >> >> >>>
> >> >> >>>     const x = v === 'foo' ? 1 : v === 'bar' ? 3 : v === 'baz' ?
> 6 : 99;
> >> >> >>>
> >> >> >>> i feel proposed switch-expressions are no more
> readable/maintainable than ternary-operators, if you follow jslint's
> style-guide.  i'll like to see more convincing evidence/use-case that they
> are better:
> >> >> >>>
> >> >> >>> ```javascript
> >> >> >>> /*jslint*/
> >> >> >>> "use strict";
> >> >> >>> const v = "foo";
> >> >> >>> const x = (
> >> >> >>>     v === "foo"
> >> >> >>>     ? 1
> >> >> >>>     : v === "bar"
> >> >> >>>     ? 3
> >> >> >>>     : v === "baz"
> >> >> >>>     ? 6
> >> >> >>>     : 99
> >> >> >>> );
> >> >> >>> ```
> >> >> >>>
> >> >> >>> here's another example from real-world production-code, where
> switch-expressions probably wouldn't help:
> >> >> >>>
> >> >> >>> ```javascript
> >> >> >>> $ node -e '
> >> >> >>> /*jslint devel*/
> >> >> >>> "use strict";
> >> >> >>> function renderRecent(date) {
> >> >> >>> /*
> >> >> >>>  * this function will render <date> to "xxx ago"
> >> >> >>>  */
> >> >> >>>     date = Math.ceil((Date.now() - new Date(date).getTime()) *
> 0.0001) * 10;
> >> >> >>>     return (
> >> >> >>>         !Number.isFinite(date)
> >> >> >>>         ? ""
> >> >> >>>         : date < 60
> >> >> >>>         ? date + " sec ago"
> >> >> >>>         : date < 3600
> >> >> >>>         ? Math.round(date / 60) + " min ago"
> >> >> >>>         : date < 86400
> >> >> >>>         ? Math.round(date / 3600) + " hr ago"
> >> >> >>>         : date < 129600
> >> >> >>>         ? "1 day ago"
> >> >> >>>         : Math.round(date / 86400) + " days ago"
> >> >> >>>     );
> >> >> >>> }
> >> >> >>>
> >> >> >>> console.log(renderRecent(new Date().toISOString())); // "0 sec
> ago"
> >> >> >>> console.log(renderRecent("2019-02-28T05:32:00Z")); // "10 sec
> ago"
> >> >> >>> console.log(renderRecent("2019-02-28T05:27:30Z")); // "5 min ago"
> >> >> >>> console.log(renderRecent("2019-02-28T05:14:00Z")); // "18 min
> ago"
> >> >> >>> console.log(renderRecent("2019-02-28T03:27:00Z")); // "2 hr ago"
> >> >> >>> console.log(renderRecent("2019-02-12T05:27:00Z")); // "16 days
> ago"
> >> >> >>> console.log(renderRecent("2018-02-28T05:27:00Z")); // "365 days
> ago"
> >> >> >>> '
> >> >> >>>
> >> >> >>> 0 sec ago
> >> >> >>> 10 sec ago
> >> >> >>> 5 min ago
> >> >> >>> 18 min ago
> >> >> >>> 2 hr ago
> >> >> >>> 16 days ago
> >> >> >>> 365 days ago
> >> >> >>>
> >> >> >>> $
> >> >> >>> ```
> >> >> >>>
> >> >> >>> On 27 Feb 2019, at 13:12, David Koblas <david at koblas.com> wrote:
> >> >> >>>
> >> >> >>> Just for folks who might be interested, added a babel-plugin to
> see what was involved in making this possible.
> >> >> >>>
> >> >> >>> Pull request available here --
> https://github.com/babel/babel/pull/9604
> >> >> >>>
> >> >> >>> I'm sure I'm missing a bunch of details, but would be interested
> in some help in making this a bit more real.
> >> >> >>>
> >> >> >>> Thanks
> >> >> >>>
> >> >> >>> On 2/26/19 2:40 PM, Isiah Meadows wrote:
> >> >> >>>
> >> >> >>> You're not alone in wanting pattern matching to be
> expression-based:
> >> >> >>>
> >> >> >>> https://github.com/tc39/proposal-pattern-matching/issues/116
> >> >> >>>
> >> >> >>> -----
> >> >> >>>
> >> >> >>> Isiah Meadows
> >> >> >>> contact at isiahmeadows.com
> >> >> >>> www.isiahmeadows.com
> >> >> >>>
> >> >> >>> -----
> >> >> >>>
> >> >> >>> Isiah Meadows
> >> >> >>> contact at isiahmeadows.com
> >> >> >>> www.isiahmeadows.com
> >> >> >>>
> >> >> >>>
> >> >> >>> On Tue, Feb 26, 2019 at 1:34 PM David Koblas <david at koblas.com>
> wrote:
> >> >> >>>
> >> >> >>> 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>
> 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>
> 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>
> 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>
> wrote:
> >> >> >>>
> >> >> >>> Hi,
> >> >> >>>
> >> >> >>> This would be covered by 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>
> 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
> >> >> >>> https://mail.mozilla.org/listinfo/es-discuss
> >> >> >>>
> >> >> >>> _______________________________________________
> >> >> >>> es-discuss mailing list
> >> >> >>> 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>
> 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>
> 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>
> wrote:
> >> >> >>>
> >> >> >>> Hi,
> >> >> >>>
> >> >> >>> This would be covered by 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>
> 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;
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20190302/c7ff9492/attachment-0001.html>


More information about the es-discuss mailing list