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
cont...@isiahmeadows.com
www.isiahmeadows.com

On Thu, Feb 28, 2019 at 12:40 PM Naveen Chawla <naveen.c...@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 <isiahmead...@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
>> cont...@isiahmeadows.com
>> www.isiahmeadows.com
>>
>> On Thu, Feb 28, 2019 at 9:23 AM Naveen Chawla <naveen.c...@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 <da...@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 <kaizhu...@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 <da...@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
>> >>> cont...@isiahmeadows.com
>> >>> www.isiahmeadows.com
>> >>>
>> >>> -----
>> >>>
>> >>> Isiah Meadows
>> >>> cont...@isiahmeadows.com
>> >>> www.isiahmeadows.com
>> >>>
>> >>>
>> >>> On Tue, Feb 26, 2019 at 1:34 PM David Koblas <da...@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 <da...@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 <ljh...@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 <da...@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 <bluesh...@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 <da...@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@mozilla.org
>> >>> https://mail.mozilla.org/listinfo/es-discuss
>> >>>
>> >>> _______________________________________________
>> >>> es-discuss mailing list
>> >>> es-discuss@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 <ljh...@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 <da...@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 <bluesh...@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 <da...@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@mozilla.org
>> >>> https://mail.mozilla.org/listinfo/es-discuss
>> >>>
>> >>> _______________________________________________
>> >>> es-discuss mailing list
>> >>> es-discuss@mozilla.org
>> >>> https://mail.mozilla.org/listinfo/es-discuss
>> >>>
>> >>>
>> >>> _______________________________________________
>> >>> es-discuss mailing list
>> >>> es-discuss@mozilla.org
>> >>> https://mail.mozilla.org/listinfo/es-discuss
>> >>>
>> >>> _______________________________________________
>> >>> es-discuss mailing list
>> >>> es-discuss@mozilla.org
>> >>> https://mail.mozilla.org/listinfo/es-discuss
>> >>>
>> >>> _______________________________________________
>> >>> es-discuss mailing list
>> >>> es-discuss@mozilla.org
>> >>> https://mail.mozilla.org/listinfo/es-discuss
>> >>>
>> >>>
>> >>> _______________________________________________
>> >>> es-discuss mailing list
>> >>> es-discuss@mozilla.org
>> >>> https://mail.mozilla.org/listinfo/es-discuss
>> >
>> > _______________________________________________
>> > es-discuss mailing list
>> > es-discuss@mozilla.org
>> > https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to