> It would be unthinkable for it to use pattern matching or explicit code > branching 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 [email protected] www.isiahmeadows.com On Fri, Mar 1, 2019 at 6:25 AM Naveen Chawla <[email protected]> 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 <[email protected]> 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 >> [email protected] >> www.isiahmeadows.com >> >> On Thu, Feb 28, 2019 at 12:40 PM Naveen Chawla <[email protected]> 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 <[email protected]> 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 >> >> [email protected] >> >> www.isiahmeadows.com >> >> >> >> On Thu, Feb 28, 2019 at 9:23 AM Naveen Chawla <[email protected]> >> >> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 >> >> >>> [email protected] >> >> >>> www.isiahmeadows.com >> >> >>> >> >> >>> ----- >> >> >>> >> >> >>> Isiah Meadows >> >> >>> [email protected] >> >> >>> www.isiahmeadows.com >> >> >>> >> >> >>> >> >> >>> On Tue, Feb 26, 2019 at 1:34 PM David Koblas <[email protected]> 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 <[email protected]> >> >> >>> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> >> >> >>> 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 >> >> >>> [email protected] >> >> >>> https://mail.mozilla.org/listinfo/es-discuss >> >> >>> >> >> >>> _______________________________________________ >> >> >>> es-discuss mailing list >> >> >>> [email protected] >> >> >>> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> >> >> >>> 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 >> >> >>> [email protected] >> >> >>> https://mail.mozilla.org/listinfo/es-discuss >> >> >>> >> >> >>> _______________________________________________ >> >> >>> es-discuss mailing list >> >> >>> [email protected] >> >> >>> https://mail.mozilla.org/listinfo/es-discuss >> >> >>> >> >> >>> >> >> >>> _______________________________________________ >> >> >>> es-discuss mailing list >> >> >>> [email protected] >> >> >>> https://mail.mozilla.org/listinfo/es-discuss >> >> >>> >> >> >>> _______________________________________________ >> >> >>> es-discuss mailing list >> >> >>> [email protected] >> >> >>> https://mail.mozilla.org/listinfo/es-discuss >> >> >>> >> >> >>> _______________________________________________ >> >> >>> es-discuss mailing list >> >> >>> [email protected] >> >> >>> https://mail.mozilla.org/listinfo/es-discuss >> >> >>> >> >> >>> >> >> >>> _______________________________________________ >> >> >>> es-discuss mailing list >> >> >>> [email protected] >> >> >>> https://mail.mozilla.org/listinfo/es-discuss >> >> > >> >> > _______________________________________________ >> >> > es-discuss mailing list >> >> > [email protected] >> >> > https://mail.mozilla.org/listinfo/es-discuss On Fri, Mar 1, 2019 at 6:25 AM Naveen Chawla <[email protected]> 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 <[email protected]> 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 >> [email protected] >> www.isiahmeadows.com >> >> On Thu, Feb 28, 2019 at 12:40 PM Naveen Chawla <[email protected]> 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 <[email protected]> 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 >> >> [email protected] >> >> www.isiahmeadows.com >> >> >> >> On Thu, Feb 28, 2019 at 9:23 AM Naveen Chawla <[email protected]> >> >> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 >> >> >>> [email protected] >> >> >>> www.isiahmeadows.com >> >> >>> >> >> >>> ----- >> >> >>> >> >> >>> Isiah Meadows >> >> >>> [email protected] >> >> >>> www.isiahmeadows.com >> >> >>> >> >> >>> >> >> >>> On Tue, Feb 26, 2019 at 1:34 PM David Koblas <[email protected]> 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 <[email protected]> >> >> >>> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> >> >> >>> 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 >> >> >>> [email protected] >> >> >>> https://mail.mozilla.org/listinfo/es-discuss >> >> >>> >> >> >>> _______________________________________________ >> >> >>> es-discuss mailing list >> >> >>> [email protected] >> >> >>> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> >> >> >>> 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 >> >> >>> [email protected] >> >> >>> https://mail.mozilla.org/listinfo/es-discuss >> >> >>> >> >> >>> _______________________________________________ >> >> >>> es-discuss mailing list >> >> >>> [email protected] >> >> >>> https://mail.mozilla.org/listinfo/es-discuss >> >> >>> >> >> >>> >> >> >>> _______________________________________________ >> >> >>> es-discuss mailing list >> >> >>> [email protected] >> >> >>> https://mail.mozilla.org/listinfo/es-discuss >> >> >>> >> >> >>> _______________________________________________ >> >> >>> es-discuss mailing list >> >> >>> [email protected] >> >> >>> https://mail.mozilla.org/listinfo/es-discuss >> >> >>> >> >> >>> _______________________________________________ >> >> >>> es-discuss mailing list >> >> >>> [email protected] >> >> >>> https://mail.mozilla.org/listinfo/es-discuss >> >> >>> >> >> >>> >> >> >>> _______________________________________________ >> >> >>> es-discuss mailing list >> >> >>> [email protected] >> >> >>> https://mail.mozilla.org/listinfo/es-discuss >> >> > >> >> > _______________________________________________ >> >> > es-discuss mailing list >> >> > [email protected] >> >> > https://mail.mozilla.org/listinfo/es-discuss _______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

