[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)