[HN Gopher] Java record pattern matching in JDK 19 ___________________________________________________________________ Java record pattern matching in JDK 19 Author : SemanticStrengh Score : 115 points Date : 2022-05-14 15:29 UTC (7 hours ago) (HTM) web link (openjdk.java.net) (TXT) w3m dump (openjdk.java.net) | zelphirkalt wrote: | Another feature, that Java finally adopts, after decades of not | adopting it. More and more language features and concepts are | being introduced, finally exposing Java-only programmers to them. | Lambdas, pattern matching, project Loom, at some point in the | future, Java might be called a modern language. Good for Java and | Java programmers. | | Just checked some other languages: | | - SRFI (Scheme Request for Implementation): | https://srfi.schemers.org/srfi-200/srfi-200.html | | Syntax: | | > | ($ record-name pat_1 ... pat_n) a record | | - GNU Guile: | https://www.gnu.org/software/guile/manual/html_node/Pattern-... | | Seems to be implementing the SRFI: | | > | ($ record-name pat_1 ... pat_n) a record | | - Rust: https://doc.rust-lang.org/book/ch18-03-pattern- | syntax.html and https://doc.rust- | lang.org/reference/patterns.html#struct-pat... | | > We can also use patterns to destructure structs, enums, and | tuples to use different parts of these values. Let's walk through | each value. | | > Struct patterns match struct values that match all criteria | defined by its subpatterns. They are also used to destructure a | struct. | pron wrote: | > Another feature, that Java finally adopts, after decades of | not adopting it. | | Back in 1997, James Gosling published an article that serves as | a blueprint to Java's evolution to this day: | https://www.win.tue.nl/~evink/education/avp/pdf/feel-of-java... | He explained it further, as related by Brian Goetz in the first | 20 minutes of this talk: | https://www.youtube.com/watch?v=Dq2WQuWVrgQ | | In short, Java attempts to be "a wolf in sheep's clothing," | with a state-of-the-art, innovative runtime, wrapped in a | language that's intentionally conservative. Java the _language_ | only adopts features that have already proven themselves as | worthwhile elsewhere, and when mainstream programmers are ready | for them. We don 't always live up to that standard, but we | try. | | So another way of putting what you said is that this is another | feature that has proven itself enough, for long enough, and | that's matured enough for Java to adopt it. Many if not most | programming language features don't make it to that stage. | | The flip side is to examine which features have never made it | to Java and probably never will (at least, they're not on our | long-term roadmap). Those include, among others, macros, | extension methods, first-class properties, and async/await. | SemanticStrengh wrote: | there is nothing to be proud of about lacking extension | methods. Kotlin has them and it allow to make amazing APIs | that are much more ergonomic/reduce cognitive overhead. | pron wrote: | I personally think there's much to be proud of in lacking | _any_ feature, as long as you deliver what your users | expect, especially if the number of users is very large. | After all, the goal of a mainstream programming language is | not to have as many features as possible, but _as few as | necessary_ , where "necessary" takes into account both the | common software requirements of the era (which are also | shaped by the hardware characteristics of the era) as well | as the expectations and habits of the majority of | programmers at that point in time. | | I can tell you that if Java's language team encounters some | language feature that solves a particular problem, they'd | rather spend spend several years thinking how to _avoid_ | adding that feature while still addressing the problem, | than the six months needed to implement it. A good strategy | for doing that is to wait, and try to think of ways to | solve multiple problems with one feature (even if | imperfectly) rather than solve multiple problems with | multiple features. | _old_dude_ wrote: | The same feature does not entail the same tradeoff | depending on the languages. | | For Kotlin, extensions methods are essential otherwise you | can not extend existing Java types with Kotlin types. | | For C#, you need extension methods for LINQ because | modifying the .Net runtime was not an option at that time. | | For Java, changing the VM is not an issue, instead of | extension methods you add default methods which can be | overridden by implementations. | | Same feature, different tradeoffs. | kaba0 wrote: | I think Kotlin went the easy way with extension methods. | Scala's solution is much more elegant with implicits | (especially now with Scala 3). | SemanticStrengh wrote: | I'd be very interested in a comparison between scala 3 | using/given and Kotlin new context receivers https://gith | ub.com/Kotlin/KEEP/blob/master/proposals/context... | elric wrote: | > Another feature, that Java finally adopts, after decades of | not adopting it | | Java has been steadily moving in this direction for quite a few | years now. It's tricky business. There's the language proper, | and there's the JVM, which are interdependent. Both are aiming | to remain backwards compatible. Introducing new major language | features is not an easy feat. | pavelbr wrote: | C# has been adding new major language features all the time | since its inception, including pretty much everything we are | seeing being added to Java these days. | Skinney wrote: | Yeah, and this "kitchen sink" approach is partly why I | stopped writing C#. Same thing is turning me away from JS. | | It's exhausting trying to stay up-to-date with the | language, in addition to changes in the frameworks and | tools on top of the challenges of my day job. | | I might be showing my age, but I've come to appreciate that | features come after long and careful consideration, and not | every single release. | grishka wrote: | What I love about Java though, is that this new syntax is very | clear and its intentions are obvious when you're reading | someone else's code. It doesn't require you to hold a mountain | of context in your head at all times like Swift and Kotlin do. | Yes, it's verbose at times. But verbosity is a good property | for a programming language because it allows the code to be | read and understood with ease outside of an IDE. | jeroenhd wrote: | Most Java is very easy to comprehend, but then you have | things like implicit finals and whatever you call the `List<? | extends Something>` language construct. I think most Java is | very boring, functional code with some notable exceptions | related to threading and the typing system. It gets the job | done, but often in an ugly, roundabout way. | | The way `Optional` is implemented and the roundabout way to | just grab the first item in a list | (`list.stream().findFirst()` or `var e = null; if | (!list.isEmpty()) e = list.get(0);`?) where other languages | have added helpers years ago. Or, even worse, the lack of | tuples, leading to your average medium-sized Java project | containing five different implementations of Tuple/Pair. | There are also runtime restrictions that sometimes crop up | because Oracle can't break compatibility (type erasure, for | example). | | If code clarity was the only metric for language quality then | we'd all be writing some BASIC derivative. I don't think more | modern languages like Swift and Kotlin are all that | applicable to all areas where Java shines, but ever since | dotnet went open source and cross platform I'm really | starting to wonder why anyone still bothers with Java. | Jach wrote: | I was almost with you up until the end then I had to just | shake my head. I mean, it's readable syntax and doesn't | require some crazy new sigils or operators, it's "fine" | though I'm also shaking my head at the scope rules for these | bindings. Similarly I'm ok with the "fine" syntax of | Optional, and being explicit with my Optional.orElse()'s, | rather than introducing an 'elvis operator' or some | bikeshedded derivative. Though I wouldn't mind such things -- | I'm glad Java keeps evolving useful things anyway, but it | does wear on you (or at least me) to have to speak them (or | even to tell your IDE to speak them on your behalf) as if | your mouth was full of sand or to read them as if they're a | high school student's essay obviously padded to reach some | word count minimum. | | If I came across this new thing organically, I could go "ah, | neat, we have that now" and not necessarily need to go look | up the JEP (meanwhile Python's PEP 636 had me going wtf) -- | though over time I'd expect to come across it in a negative | context where the original programmer made a scope mistake | because they _didn 't_ read the JEPs, or because they tried | to make a change _without_ their IDE 's assistance where | through various means it could have pointed out shadowing or | scope concerns, that I now have to fix. | | It's in no minor part thanks to Java's verbosity that the | overall Java ecosystem is so verbose. Having mostly non- | confusing syntax whose meaning you can mostly guess at on | first exposure is nice, yes, but isn't so helpful for the | more important aspect of having non-confusing programs. For | that you really want a more concise and tasteful language | over a verbose one. Anyway, I've found that for anything non- | trivial about the program itself, I'm going to need an IDE | because the meat of the thing is going to be verbosely spread | out in many places (sometimes for good reasons, at least in | the Java world). Sure, after I acquire the mountain of | (program) context, I can review small changes even on paper | printouts, but that's true of most anything. | | Verbosity is not a good property for a language to have in | general -- Java itself admits this, otherwise we wouldn't | have so many shortcuts in syntax like omitting this, or java | 7's diamond operator or try-with-resources or catching | multiple exceptions or for-each syntax, or java 8's lambdas | and special syntax for simple lambdas, or java 9's var, or... | And of course, almost always in some other more concise | language a concept is much clearer. There's a reason pseudo- | code isn't written to look like Java. | [deleted] | mabbo wrote: | It's not the feature that excites me, it's the pace of Java | language improvements. The 6-month cycle of versions, the whole | process of letting experimental features in for a couple versions | to test, refine, and likely accept, it's all really _working_ , | you know? We're _getting_ stuff that 's been so long desired, and | it's happening quickly enough to be exciting but not so fast that | we're overwhelmed and things are breaking. | | People often say that Java 8 was the big important update to the | language (streams, lambdas, java.time, and more), but I think | Java 9, which began this process was the true rebirth of the | language. | eecc wrote: | Cool, thanks Java gatekeepers for procrastinating your change of | mind long enough to save face. | | In the meantime I wish we had a community that could evolve at | that sweet, optimal pace, a promise that the Javascript one | completely blew. Rust? | [deleted] | cutler wrote: | Despite recent improvements including raw string literals it | beggars belief how Java still requires regex metacharacters to be | escaped. Until that's fixed Java is not an option for me. | [deleted] | hn_throwaway_99 wrote: | Cool to see Java getting these features. After having been a Java | dev most of my life, and then moving to Typescript years ago, | it's hard to believe I went so long without this. | | Related, Typescript is the only language I know of that through | flow analysis does _not_ require you to redefine the variable. | E.g. you can do something like if (typeof foo === | 'string') { //Typescript knows foo is a string here | } | | All the other languages I know of, like this proposal for Java, | require the variable to be redefined. I personally find the | Typescript way, as VSCode will give you appropriate type warnings | in the right places, easier to use in practice. Just curious if | there are any other languages that do it like TS. | papercrane wrote: | The Typescript way would only work for local variables in Java. | Since another thread might update a field between the | instanceof check and the use of the field. | SemanticStrengh wrote: | those cases are rare. Defensive copying should be optin, not | the default. Java really deep copy objects for even the most | basic instanceof checks?? | kaba0 wrote: | You can't change the object's type in Java, so if you hold | on to the same reference it will be safe to use after the | instanceof check. | zarzavat wrote: | You're definitely holding it wrong if you have polymorphic | fields in your lock-free shared memory. Or at least holding | it weirdly. | gizmo686 wrote: | Thats the problem with language design. If the language | allows something, it needs to correctly support it; even if | actually doing it is a bad idea. | swaranga wrote: | There are some edge cases because of which this had to be done, | I think. For example calling static methods via the instance | variables, the actual method called would be the static type of | the variable at compile time and not the actual type at | runtime: public static void main(String[] | args) { Parent instance = new Child(); | if (instance instanceof Child p) { | instance.print(); // prints Parent p.print(); | // prints Child } } static | class Parent { static void print() { | System.out.println("Parent"); } } | static class Child extends Parent { static void | print() { System.out.println("Child"); | } } | | Hence, with flow typing, existing code could break in subtle | ways. | hilbertseries wrote: | If you're writing code calling static methods on instances of | classes, you deserve to have that code broken. | yarg wrote: | Does java provide warnings against calling static methods on | Objects? | smarks wrote: | Yes, if javac is given the `-Xlint:static` option. | SemanticStrengh wrote: | How does Kotlin solve those use cases? | | > instance.print(); // prints Parent | | why? the parent print should be shadowed/overidden by the | child bruh | spullara wrote: | statics don't override | SemanticStrengh wrote: | oops my bad | danachow wrote: | That's not dataflow analysis. It looks like a cast similar to | something like in C# ie: if (foo is string as foo) where the | "as foo" scoped variable is implicit. It's basically implicitly | redefining the variable with limited scope. Type guards are a | slick feature but it is just an expression match and some | syntactic sugar. Even user defined type guards in typescript | have to be explicitly declared as such. | | This would be more an example of CFA. const a = | "string"; if (typeof v === a) | hn_throwaway_99 wrote: | It's not just a simple cast, but I should have used the | correct term which is "control flow analysis". It's not just | redefining the variable, control flow analysis works in lots | of different places besides just typeof checks, and is | possible in many cases because TS is structurally typed, not | nominally typed. | jung_j wrote: | Java 14 does have something similar | | https://openjdk.java.net/jeps/305 | hn_throwaway_99 wrote: | No, Java requires you to redefine the variable, i.e. | if (obj instanceof String s) { // s is a String here, | but obj is not } | SemanticStrengh wrote: | but is it a deep copy?? | sebazzz wrote: | It is not a copy. It still references the same object. | Pet_Ant wrote: | That I would say still counts as "similar" not "the same" | danachow wrote: | That's the same, just that the scoped definition is | implicit. | hn_throwaway_99 wrote: | No, that's the entire point of my question. In Typescript | (and Kotlin, as others have noted), the type system knows | _within the scope of that if statement_ that obj is a | string, so it lets you call string-specific methods on | obj withOUT introducing the new variable s. | danachow wrote: | What I'm saying is that this: if (typeof | obj === 'string') { // obj is a string } | | is really not anything meaningfully different than this | if (obj is string as obj) { // as in C# // obj is | a string (shadowing the outer scoped obj) } | | or this if (obj instanceof String obj) { | // obj is a String here } | | you can imagine a pseudo TypeScript language like this | if (typeof obj === 'string' as obj) { // obj is a | string } | | Actual TypeScript merely allows you to elide the "as obj" | and all it needs to trigger this is the "typeof obj === | <string literal>" inside of an if expression. This can be | done by a simple syntactic replacement, it doesn't | require control flow analysis to get this specific | feature. But yes, if you have a more general computed | expression, that would apply, but that was not the case | you were stating. Ie the variable isn't the issue | (redefining in this case seems like a distinction without | a difference)... However this does work in TS, which is a | demonstration of CFA: const isStr = | typeof obj === "string"; if (isStr) { | // obj is str } | | For what it's worth I think CFA is useful in TypeScript | based on it at its core being a structural typed bandaid | over JS, but I think these specific CFA type narrowing | features are redundant in stronger typed languages. | Smaug123 wrote: | F# also has: let foo : obj = failwith "" | match foo with | :? SomeType as blah -> // | use blah : SomeType | | (You're allowed to just use the identifier `foo` in the match | arm.) | halfmatthalfcat wrote: | As does Scala: match thing { case | a: String => // use a as string case a @ | MyCaseClass(b: String, c, d) => // use a as the | instance of MyCaseClass or use b as a string } | dwaite wrote: | Some of this is a consequence of how typescript works - it | carries any structural constraints it can find forward in an | advisory capacity, because it is somewhat decoupled from the | quite-dynamic runtime behavior of the javascript engine. | | It isn't even block-based scoping in the flow analysis above - | if in your block there was the code foo = 1; the typescript | engine would then expect that foo will behave like a Number at | runtime. | | I haven't dived in deep enough, but I suspect foo could even | have different structural type information within the same | expression, e.g. a ternary (typeof foo === 'string') ? | something(foo) : somethingelse(foo) | Squarex wrote: | Kotlin is the same as typescript. | pkulak wrote: | Kotlin does that as well, and it's a JVM language. | arthurcolle wrote: | > All the other languages I know of, like this proposal for | Java, require the variable to be redefined. | | can you give a few examples? This makes no sense to me and I've | touched quite a few ecosystems in my time. Maybe I am | misunderstanding but my current understanding makes this seem | not realistic | TheMatten wrote: | And of course, Haskell has equivalent too: | case eqT @a @String of Just Refl -> ... | moomin wrote: | Refinement typing (the TS way) is relatively common in type | systems that sit on top of dynamic languages because basically | they have no choice. Binding to a new variable, however, is a | heck of a lot easier to analyse so tends to be done in | languages that don't need to implement refinement typing. | | A couple of interesting exceptions: explicit interfaces make it | impractical in C#, and there's a project called liquid Haskell | that adds refinement typing on top of an already strong type | system. | SemanticStrengh wrote: | Don't be mistaken, Typescript do not has proper pattern | matching support, The proposal is far from being adopted | https://github.com/tc39/proposal-pattern-matching | | > Related, Typescript is the only language I know of that | through flow analysis does not require you to redefine the | variable. E.g. you can do something like | | This is called smart casting and is widely used in Kotlin | viewfromafar wrote: | The PL crowd calls that type system feature "occurrence | typing." | SemanticStrengh wrote: | yes or flow typing https://en.wikipedia.org/wiki/Flow- | sensitive_typing It probably overlap with the research on | gradual typing too | PartiallyTyped wrote: | Mypy (Python) does this as well. VSCode and PyCharm provide | typehints after if isinstance(foo, str): | # code | dehrmann wrote: | Sometimes. If foo isn't local scope, this won't work because | it could be modified in another thread. | saghm wrote: | In my compilers class, this is how we did static downcasting | for the toy language we created (I think it was called Oat?). I | think it's clever, but I find that I prefer mechanisms that | rebind the variable for clarity purposes. It's super easy IMO | to accidentally gloss over something as being just a regular if | statement rather than something that's actually statically | changing the type of the variable compared to having different | syntax than just a regular conditional. I also tend to prefer | being able to look at a variable's usage and then look back to | the time it was initialized and know that it's still the same | type; having the type change only within a given scope without | any explicit binding seems like something I'd mess up a lot, | especially when reviewing code I didn't write myself. | skybrian wrote: | Dart also does this. | markdog12 wrote: | And it's getting patterns too: https://github.com/dart- | lang/language/tree/master/working/05... | blacksmithgu wrote: | I love seeing modern language features coming to Java! Sadly, I | suspect it will be at least a decade before I see Java 19 used | anywhere I work... | quilombodigital wrote: | I am an old school java developer. Can someone explain me why | this is a "feature"? I can remember by counting my fingers the | times I had to use "instanceof", and it was some classical | reflection/injection/instantiation framework 'vodu'. If you are | using instanceof in a normal java program, you are just making it | wrong. It looks like some new javascript guys arrived in the | block and are trying to make java look something messy like | Scala. What real world problem is this trying to solve? Are you | just fucking bored because you are all out of ideas and every JDK | release we need "something"? Why these JEPs only have | "boxes,rectangles,A,B,I" class examples and not a simple real | world class scenario? Why we need to make java "friendly" to work | with generic objects? it should be hell! I cant wait for JDK 50. | mathgladiator wrote: | I wish they had better examples, so here is one. Suppose you | are making a scene graph, and you want to have a visitor and | run code based on the type of the nodes in the graph. Well, | consider two approaches. The first approach is to use a bunch | of ifs and instanceof, but this isn't clean and it is fragile. | The second approach is to make an interface that has all the | types listed under a handler (void handle(Type1 t), void | handle(Type2 t), ...) and then write some boiler plate code to | do the dispatch. | | This feature aims at the conciseness of first model | (instanceof) with the safety of the second approach (i.e. all | types are handled). | | I would love this feature for my project! ( https://www.adama- | platform.com ) since I use Java to implement a programming | language. | quilombodigital wrote: | This is the point, you dont consider the instanceof approach, | is just wrong. You already know your types in advance. | equalsione wrote: | > If you are using instanceof in a normal java program | | In applications yes, but instanceof is heavily used if you | write frameworks. | | And as someone else has mentioned, the more functional style | java you write the more use you start to make of instanceof | hztar wrote: | you sound like a Cobol developer I once knew.. RIP | quilombodigital wrote: | This is true.... Old guys know nothing... for years we told | the javascript guys the mess they were doing, and voila, all | dynamic languages suddenly started to convert into | statically-typed, and at the end, they have this webassembly, | that runs in a schizophrenia-type VM wannabe. Congrats. You | lost 10 years of your life because you didnt listen to us | when we said that we have learned something from Self and | Smalltalk. | Skinney wrote: | > and voila, all dynamic languages suddenly started to | convert into statically-typed | | This is... just wrong. | | Plenty of people are using JS without any sort of typing | whatsoever. Other dynamic languages, like Clojure, Gradle, | Elixir, Pharao (a smalltalk), just to mention a few, are | still going strong. | | > they have this webassembly, that runs in a schizophrenia- | type VM wannabe | | wasm is mostly being used as a target for C(++), Rust and | even C# programs that want to run in the browser. It's | there to expand the reach of the browser. Most JS projects | don't touch the stuff. | jstimpfle wrote: | > wasm is mostly being used as a target for C(++) | | because... JS isn't good enough? | wiseowise wrote: | > This is true.... Old guys know nothing... for years we | told the Java guys the mess they were doing, and voila, all | OOP languages suddenly started to move to functional | paradigm. Congrats. You lost 10 years of your life because | you didnt listen to us when we said that we have learned | something from ML and Scheme. | quilombodigital wrote: | good point... but I was not talking about OOP, I was | talking about dynamic typing versus static typing. :) | jayd16 wrote: | The sealed interface, final implementation case is an | interesting one to inspect. Now you can, for example, write a | parser with a fixed set of tokens and write switches that | exhaustively handle every token. You now get compile time | guarantees. | quilombodigital wrote: | ok... so you save a few lines in a parser. program your | language for the 0.005% developers | jayd16 wrote: | It's just an example... | | And you don't seem to understand that it's about the safety | of the exhaustive check not just the sugar. | kaba0 wrote: | You really could do away with the arrogance. | quilombodigital wrote: | I dont think saving a few lines for a very rare corner | case is a strong reason to add a language feature | jstimpfle wrote: | Maybe they have a point? Arrogance != Wrong in Your | Opinion. | kaba0 wrote: | Sure, though as I mentioned in other comment, pattern | matching is basically a better Visitor pattern. Which is | while not the most common pattern, is not that much of a | niche either. | halfmatthalfcat wrote: | "...look something messy like Scala", I feel bad you feel this | way as Scala is an incredibly powerful and elegant language. | | It's ironic because you're throwing shade at Javascript when JS | developers are doing the same thing against Typescript. Fearing | what you don't know or understand under the guise that change | is bad or things are "good enough". | quilombodigital wrote: | I agree Scala is very powerful. I said messy because it is | "too powerful", added too many features. I think this is | their mistake. I respect the community, but can show my | opinion as you can about java. | kaba0 wrote: | I really don't feel that Scala has too many features. It is | a relatively small language which is very elegant due to | having almost no edge cases. Sure, due to not having many | features yet being very expressive it has to have very | powerful language primitives that can be abused, but I | really don't think that it is as bad as its name. | wiseowise wrote: | > show my opinion as you can about java. | | Showing your opinion doesn't make it immune from critique. | quilombodigital wrote: | true | dopidopHN wrote: | I really liked scala... until I had a to maintain a large | and << old >> code base in it. | | I think messy fits. | dboreham wrote: | "Write-only language" | grumpyprole wrote: | Java is also a messy language and the reason for a lot of | the mess in Scala. If you want elegance, then you should | probably learn something like Haskell. | quilombodigital wrote: | can we have a not-messy-not-elegant language? :) | orthoxerox wrote: | Eiffel? | Frost1x wrote: | Highly compositional design patterns in Java. When you have a | fairly large set of custom types that are hierarchically | structued in nature, it can be quite useful. | | In most standard IT applications it may be less common. I've | seen it used fairly well in scientific applications. There are | of course other ways of approaching working with and acting on | wide taxonomies of objects that could exist but this is one of | them. | kaba0 wrote: | instanceof is but one possible use case. Arguably the most | useful part of pattern matching is inside switch expressions, | and there is an equivalence between the Visitor pattern and | this, but the latter is much more readable and maintainable. | Sure, the visitor pattern is not that often used, but in | certain niches that make use of ASTs often it is pretty much a | must. | jstimpfle wrote: | I've never been a fan of Java due to the GC and the boilerplate | and runtime overhead (time but also space) that come with it. | But I've always had respect for it because it felt so minimal | and consistent in its own way, bulky but solid kinda like a BMW | car. | | Now that functional stuff and instanceof fluff is something | else. I don't like it either. | kaba0 wrote: | Unless you only prefer low-level languages, Java's runtime is | anything but bulky. It is one of the fastests runtimes out | there, so runtime overhead is relative. | [deleted] | rr808 wrote: | I kinda feel the same. Modern Java is written like some | Python/JS Mashup. Its one reason old code bases are a huge mess | because code is written in many different styles. | BlackFly wrote: | It shows the majority of its strength in switch statements. You | can mostly just use the instanceof for a one line destructuring | of a compound object into its constituents. The corresponding | rust statement is the `if let` or `if case let` if you are more | of a swift fan. Generally you would use it with sum types which | were previously extremely nasty to work with in Java but are | more useful now with sealed classes. | | The pattern shows up a lot with result and option types but you | can do it any other time where a tagged union makes sense. The | classic way to do a tagged union in Java was just a personal | taste amongst bad options: tagging interface and instanceof on | implementations or an encapsulating class that will return null | (or throw an exception) if the gets are called for the types | which aren't encapsulated. | | If in your career you never needed to enumerate cases that | required different data in each case and you couldn't see how | binding those requirements into an invariant via the type | system was helpful then you probably won't use these new | features either. Some people thought it was helpful but the | boilerplate cost was too high so wouldn't do it in practice (I | am in this category). | | Edit: you could also make tagged unions more type safe with | callbacks, but then implementing a closure to pull the value | out of the callback was just annoying. | quilombodigital wrote: | "If in your career you never needed to enumerate cases that | required different data..." . Maybe one or two times... but | it is not like "hey, it is impossible", or "shit, I have to | write 10 more lines" in this rare code I will never put my | eyes again. What I get angry is that people will start to use | everywhere, in places they should not be using. because the | guy did not wanted to stop five minutes to _think_ about it. | The river flows through the easiest path, but this does not | means it is the smartest path. | Twisol wrote: | Unfortunately, I've seen plenty of Java 8 code where people | did not "stop five minutes to think about it". I don't | think any language can protect us from ourselves. | | It's fair that you've found sensible ways to achieve your | goals without ever _needing_ pattern matching. Nobody | should fault you for that. But can you grant that other | developers might have other sensible ways to achieve other | goals (or sometimes other ways to achieve the same goals!)? | | I think most Java developers will be familiar with the | visitor pattern. In almost all cases (there are | exceptions!), I detest it; I find sum types with pattern | matching to be a far superior way to say what I mean. Java | added `sealed` interfaces recently, so you can actually | model a closed family of types. Now pattern matching closes | the loop, giving you a supremely ergonomic way of | dispatching over that closed family without using a | visitor. | | Maybe it's not clear from other responses, but the part of | the JEP about an "exhaustive switch" is critical here. Java | statically guarantees that you've handled each member of | your closed family, just like if you forgot to implement a | method for a visitor. | metadat wrote: | This doesn't take anything away, it just adds extra convenience | and flexibility. | quilombodigital wrote: | My problem is with the "just adds"... Scala made this | mistake, and ended with many different ways to do the same | task. It is a powerful language, but I believe languages must | have only one (or two) concise way to to things. | adra wrote: | If you wanted the idiomatic only-one-way-to-do-things | approach to do things, Java is not and has never been the | language of choice for that. Why do we have 10 different | dependency injection /logging / web frameworks? Who cares! | Let's add an 11th for good measure. I don't want java to be | idiomatic and purist conformant tedium. | | You're welcome to switch your language of choice to go if | that's really your bag. | quilombodigital wrote: | The examples you gave are not language features, are | frameworks/libraries... not the discussion. (the only | exception I can see is the "logging API", but this is | debatable) | wiseowise wrote: | > but I believe languages must have only one (or two) | concise way to to things. | | Java has none. | quilombodigital wrote: | I humbly accept the critic. :) | halfmatthalfcat wrote: | The "multiple ways of doing things" is a feature, not a bug | and something which lives in almost every programming | language. It's become a meme at this point and a lazy | argument against a language. | metadat wrote: | > It's become a meme at this point and a lazy argument | against a language. | | This might be a casual dismissal of what is in fact a | nuanced aspect of programming languages. | | Multiple ways of doing the same thing can make the | language less accessible because it becomes confusing to | reason about what the "right" way is. | | That said, this particular addition merely reduces | repetitive toil, and it follows similar existing Java | conventions, for example see the Java-7 equivalent of | Python "with-statements". | | https://stackoverflow.com/a/35116251 | quilombodigital wrote: | yep, agree with you. I become more aware of this when I | worked some years in a huge ruby project. Everything was | allowed, and with tons of DSLs you dont know anymore what | is happening. | valcron1000 wrote: | 100% agree. Using 'instance of' in Java is a terrible anti- | pattern, same as trying to do pattern matching. You should lift | that code into instance methods and let the runtime pick the | right implementation. | Fellshard wrote: | There are some cases when it's actually simpler or more | maintainable or more useful to do the dispatch locally. A | language that allows you to both is tougher to learn and can | have a higher risk of pitfalls, but also means that a | seasoned practitioner can apply the right tool in the right | situation. | | In terms of the classic 'patterns', it's the difference | between standard dispatch and the 'Visitor' pattern. There | are cases where you want to specify each case of data | structure locally, and others where you want to specify each | method of each variant locally. Welcome to the expression | problem! | | There are cases in Java where you do want a true POJO - just | a bag of structured data. This is probably a very strong | candidate for using along side that. | nchi3 wrote: | Because there are scenarios where pattern matching (or | instanceof) is the better and more ergonomic thing to use. One | obvious example I can think of is event handling. | | If anything, this is _not_ something JS devs are asking for, | but rather devs using functional languages. | Fordec wrote: | I also think of API ergonomics. Unspecified input with the | same single endpoint, while under the hood will be absolute | spaghetti, from a developer adoption standpoint can be make | or break. | | And if you're strongly typing your system rather than relying | on strings, extra so. | quilombodigital wrote: | Hum... maybe this is the reason my events usually have an | abstract base class with an eventype enum field... | grumpyprole wrote: | Sometimes it isn't desirable to scatter the logic across | many classes, or conflate the data and the handling. The | Java world has the "visitor pattern" to help deal with | that, but its double-dispatch is clunky, complex and | verbose. Pattern matching just generalises switch and makes | it more useful. Java is genuinely a better language with | this change. | misja111 wrote: | Exactly, this is what OP was trying to point out. With the | record matching feature, you don't need the extra abstract | base class anymore. | | This is not to say that abstract base classes are never a | good idea, but sometimes in Java they were only there for | the convenience of one handler method, to prevent the use | of instanceof. This didn't improve readability. That's when | the record matching can be a good improvement. | Strs2FillMyDrms wrote: | For everyone saying the visitor pattern requieres switch | statements this is false. The visitor can build its case inside | the iterface/implemetation. If the complexity is being solved by | the "housing" class that the visitor will be visiting you are not | doing enough. ___________________________________________________________________ (page generated 2022-05-14 23:00 UTC)