[HN Gopher] Why Java's Records Are Better* Than Lombok's Data an...
       ___________________________________________________________________
        
       Why Java's Records Are Better* Than Lombok's Data and Kotlin's Data
       Classes
        
       Author : gher-shyu3i
       Score  : 154 points
       Date   : 2021-05-07 15:30 UTC (7 hours ago)
        
 (HTM) web link (nipafx.dev)
 (TXT) w3m dump (nipafx.dev)
        
       | flerchin wrote:
       | Project Lombok is my bae, but of course a language included API
       | is better than an annotation processor.
        
       | roflc0ptic wrote:
       | I love that this website is trying new stuff with design. I also
       | think the TOC is terrible and distracting.
        
       | hota_mazi wrote:
       | A long winded article that really never justifies its headline.
       | 
       | Kotlin will soon be generating records in its back end, thereby
       | gaining all the advantages that it's allegedly not getting today.
        
       | andrewprock wrote:
       | I'm never understood why code generation for getters and setters
       | is so over-engineered. Heavy technologies for light work is
       | almost always more trouble than it's worth.
        
         | commandlinefan wrote:
         | Getters are setters are pointless anyway - unless you're
         | creating read-only properties by only providing getters,
         | reflexively adding a getter and a setter for every property is
         | exactly the same as just marking the property public. It's even
         | worse in the case of immutable objects (like lists or maps),
         | because the getter itself returns a reference to the mutable
         | object. Getters and setters mentality came from a horrible
         | misunderstanding of object oriented design principles and has
         | been standardized into common practice.
        
           | whatshisface wrote:
           | In languages without property support, reflexively writing
           | getters and setters is the only way to make it possible to go
           | back later and add logic to getting and setting without
           | changing the callsites. Is this a workaround for the combined
           | shackles of mismanaged enterprise environments where changing
           | callsites is impossible for some reason, and legacy language
           | environments where you have to use Java for some reason? Yes,
           | of course. But sometimes you need a workaround.
        
             | slver wrote:
             | The real question is why is the convention getFoo()
             | setFoo(foo) and not foo() and foo(foo).
        
               | swsieber wrote:
               | It makes for easier searching in small code bases with
               | stuff like grep instead of needing full language server /
               | ide support.
        
               | whatshisface wrote:
               | Not all languages have overloading.
        
               | slver wrote:
               | I'm referring to Java.
        
               | whatshisface wrote:
               | I think the pattern was adopted from languages before
               | Java which didn't have overloading.
        
             | commandlinefan wrote:
             | > go back later and add logic to getting and setting
             | 
             | Which, realistically, you're virtually never going to do -
             | at least not often enough to justify the boilerplate and
             | _especially_ in the case of things like  "records" which
             | were probably auto-generated from a schema (with obligatory
             | getters and setters) anyway. If you _did_ , you'd end up
             | confusing all of your callers who probably wrote client
             | code presuming that what they provided in the setter was
             | going to be exactly what they get back in the getter.
        
               | kmonsen wrote:
               | Agree, for a lot of code you can be pretty sure it will
               | not change. And you should be able to refactor your code
               | base, if not there are larger issues.
               | 
               | In general I subscribe to the at first make it as simple
               | as possible, when you have two examples of it being too
               | simple it is time to refactor.
               | 
               | Of course when creating libraries it is different. In
               | that case to protect users on the API surface and try to
               | make that stable.
        
               | t-writescode wrote:
               | This is true, until you're writing a library that's
               | pulled from a repository and used in several projects.
               | 
               | If you can't guarantee you're not going to break someone
               | else's code by changing:
               | 
               | foo.x to foo.getX();
               | 
               | then you should stick with properties. Now, for staying
               | inside a single package, or a single compiled unit, then
               | what you say is reasonable enough. I'd still prefer to
               | write the getters and setters, though, especially in
               | cases where it's free, like Kotlin.
        
               | commandlinefan wrote:
               | It would be better if the default were to not write
               | setters _or_ getters for any properties by default, but
               | instead to write a logical interface that properly
               | encapsulates the properties. Unfortunately, that ship
               | sailed a long time ago for Java.
        
               | slver wrote:
               | It actually happens a lot for me.
        
           | slver wrote:
           | get()/set() is the same as a public property, until you
           | change the implementation, while maintaining interface
           | compatibility, which is the point.
           | 
           | In C# you'd have a point, they have parametric properties and
           | readonly properties. So you'd favor just declaring public
           | properties.
           | 
           | But this is why context matters. And OO design principles
           | also depend on this context.
        
             | marcosdumay wrote:
             | > until you change the implementation, while maintaining
             | interface compatibility, which is the point
             | 
             | How many times have you seen that done on the real world?
             | 
             | And how many times have you seen that done, and it not
             | creating a lot of bugs because of the behavior change
             | without interface changes?
             | 
             | Personally, I've seen the first one more than zero times.
             | Not the second. Every single time somebody decided to mess
             | with a setter or a getter, it broke the systems that
             | depended on it, and things would have been much better if
             | they simply changed the interface, so the problems would
             | arrive at compile time.
        
               | slver wrote:
               | The behavior doesn't change. The implementation does.
               | Those are orthogonal.
               | 
               | And yes I see it every day. The collection interfaces in
               | Java have countless swappable implementations. Those are
               | basically getters and setters on a vector.
               | 
               | I also had to change entity storage to columnar for a
               | project. Did that. Never had to change a line of code
               | outside the entities.
        
       | RcouF1uZ4gsC wrote:
       | Trying to read in Safari iOS but most of the article text seems
       | to be missing.
        
         | JackFr wrote:
         | Completely unreadable on mobile for me.
        
           | [deleted]
        
         | bvanderveen wrote:
         | Same.
        
         | turtletontine wrote:
         | Only half the code is rendering for me as well, Firefox iOS
        
         | Reason077 wrote:
         | Try using "Reader" mode. Tap the little icon at the left of the
         | URL bar.
        
         | random42_ wrote:
         | You have to scroll the page reeeeeally slow to let the text
         | load where it's supposed to.
        
           | slver wrote:
           | So this custom code font not only looks like Apple II, but it
           | also works like Apple II. Amazing.
        
       | ilrwbwrkhv wrote:
       | That blog is hard to read for some reason.
        
       | eweise wrote:
       | Main problem I had with lombok is that it was too flexible,
       | causing me to have to read all the annotations on a class. Kotlin
       | data classes are implemented a single way so I don't need to grok
       | them individually.
        
       | cs-szazz wrote:
       | I'm not sure what it's taking about for the "with" feature:
       | https://nipafx.dev/java-record-semantics/#with-blocks
       | 
       | In Kotlin data classes, it's already implemented (just called
       | copy) https://kotlinlang.org/docs/data-classes.html#copying
        
         | kelnos wrote:
         | The annoying thing about Java here is that it doesn't have
         | default argument values, and doesn't allow you to name your
         | arguments in function calls.
         | 
         | In Scala (I don't know Kotlin, but I assume it's similar) you
         | could easily implement a copy() method yourself (and many
         | people do if they need a case-class-like thing but can't use a
         | case class) that behaves identically to the copy() method
         | provided by a case class.
         | 
         | But the semantics of that copy() method require default
         | argument values, and the ability to call functions using named
         | arguments. Java doesn't have either of those, so instead of
         | adding those features (I can understand the former being
         | controversial), I guess the plan is to add entirely new syntax
         | just for records, which IMO is a huge shame.
         | 
         | But it appears the "with" syntax is far from finalized, so it's
         | possible they'll do something better.
        
         | papercrane wrote:
         | > I'm not sure what it's taking about for the "with" feature:
         | ...
         | 
         | The author is referencing possible future work that can build
         | on the current records implementation, and the work Brian Goetz
         | is doing with pattern matching and record deconstruction. Goetz
         | has put together a draft that shows how these could be
         | combined.
         | 
         | https://github.com/openjdk/amber-docs/blob/master/eg-drafts/...
        
         | stickfigure wrote:
         | It's also implemented nicely, today, with Lombok:
         | @Value @With         public class Pair {             int left;
         | int right;         }              final Pair rightIs3 =
         | somePair.withRight(3);
        
         | giaour wrote:
         | "With" doesn't exist in Java, but it was introduced in C# 9.0
         | as part of the .NET implementation of records:
         | 
         | https://devblogs.microsoft.com/dotnet/c-9-0-on-the-record/#w...
         | 
         | I think the author is more saying that a "with" operator would
         | fit into Java record semantics but might not be compatible with
         | Lombok @Data classes or Kotlin data classes (though it looks
         | from your link that Kotlin actually does have something very
         | similar in the "copy" method).
        
         | bcrosby95 wrote:
         | It was included because changing data using records (copying it
         | except changing the fields you need to change) is a shitty
         | experience, so rather than showing the code you have to write,
         | they showed you code you may or may not in the future be able
         | to write.
        
           | dlbucci wrote:
           | Seems like an odd thing to mention. They are arguing that
           | records are better than data classes, but part of their
           | argument is "maybe, in the future, at some point, I don't
           | know, it will be as easy to do this thing with records as it
           | already is with data classes, we'll only need to add new
           | syntax and a new keyword to the language".
        
             | krzyk wrote:
             | Who is they?
             | 
             | You mean the article author? Yes, it was odd that he
             | mentioned that, but besides that not a bad feature to have
             | (but a bit wordy for my taste, I hope they'll change that).
        
       | de_keyboard wrote:
       | Great to see Records come to Java, although without the "with"
       | feature they are pretty half-baked.
       | 
       | I give it 5-10 years before we've tricked everyone into writing
       | OCaml / F#!
        
       | abledon wrote:
       | IF you're not on Java 14 yet (70% of industry?[1])... this post
       | shows two other alternatives for Lombok:
       | 
       | https://medium.com/@vgonzalo/dont-use-lombok-672418daa819
       | 
       | Autovalue & Immutables
       | 
       | [1] https://snyk.io/wp-content/uploads/jvm_2020.pdf pg 5
        
         | zoover2020 wrote:
         | Unfortunately AWS Lambda doesn't support 14 yet :/
        
           | jandrese wrote:
           | Do you care about memory leaks on a Lambda? I don't think
           | they can live long enough to even invoke the GC. I guess if
           | you're going through a lot of data you could blow your memory
           | budget and have it terminated?
        
       | grishka wrote:
       | Curious question -- why do people insist so much on fields being
       | private and there being getters and setters, even when all that
       | getters do is return the field and all that setters do is set it?
       | What kind of problem does this arrangement solve? Why not just
       | use public fields?
        
         | jorblumesea wrote:
         | getters and setters prevent other objects from modifying
         | internal properties in unexpected ways. Having that
         | encapsulation and abstraction is important for maintainable
         | code.
         | 
         | Also, getters and setters don't always modify individual
         | values. Imagine a class where we have:
         | 
         | private val firstName private val lastName
         | 
         | fun returnFullName(): return firstName + lastName
        
           | grishka wrote:
           | > modifying internal properties in unexpected ways
           | 
           | Except I'm talking about Java classes that store data. They
           | don't do any operations on it, they don't have any internal
           | state, they're more like C structs.
           | 
           | > Also, getters and setters don't always modify individual
           | values.
           | 
           | Of course. But one doesn't contradict the other.
        
         | brabel wrote:
         | I think I can answer that... it's all to do with a grand view
         | that the Java original designers had about what objects should
         | look like, in what became known as Java Beans. There's a
         | spec[1] and everything.
         | 
         | They wanted to be able to write framework code that could
         | introspect Java beans and expose them directly in a user
         | interface, amongst other things, allowing users to modify them,
         | create them, delete them and even compose them to create their
         | own applications... they had even imagined there could be
         | marketplaces where you could _buy_ Java beans to add to your
         | program, or even to modify your other beans to give them extra
         | power... getters and setters were part of that - they needed to
         | know how to obtain and change the state of an Object, but how
         | the Object internally handled such state changes were up to the
         | Object itself (what we now call encapsulation)... this was
         | similar to how Smalltalk worked and that was an inspiration for
         | the Java beans specification... all this never really turned
         | out the way they wanted, of course, but have a read of the Java
         | beans spec to get a better idea of what they had in mind if you
         | don't fully understand it yet.
         | 
         | With time, people forgot completely about Java beans, but for
         | whatever reason, getters and setters sticked around to this
         | day. Many Java developers today think Java beans are just
         | classes with a bunch of getters/setters and never probably
         | heard of PropertyChangeListener, VetoableChangeListener and the
         | other parts of the Java beans spec (some of it lives on in
         | Swing).
         | 
         | If you write Java today and just want to expose some data,
         | yeah, just go with public fields if you can't use Java 16
         | records yet... if you ever need to change how you internally
         | store information, just refactor that to a setter if you really
         | must (it will never happen).
         | 
         | [1] https://www.oracle.com/java/technologies/javase/javabeans-
         | sp...
        
         | blacktriangle wrote:
         | This protects you from changes to the internal representation
         | of state in the future. Direct field access totally blows away
         | encapsulation.
        
           | grishka wrote:
           | So, uh, do a usage search before changing stuff? You'll have
           | to, anyway.
        
             | erik_seaberg wrote:
             | That works if your class is never used outside your own
             | organization, but the API of published code needs to be
             | changed more gracefully using semver.
        
             | kaba0 wrote:
             | Not necessarily agree with private fields, but that is not
             | an option for library writers.
        
         | lowbloodsugar wrote:
         | Freedom to change.
        
         | highwind wrote:
         | Only argument I heard, not that I agree but, is future proofing
         | by abstraction. What if a simple getter evolves into something
         | more complex. Then You'd have to refactor all the places where
         | it was using the fields.
         | 
         | I personally never had to do this so I'm not sure if this is a
         | real benefit.
        
         | dragonwriter wrote:
         | Depending on the language, getters and setters may not be
         | source and/or binary compatible with fields from the client
         | side, so if you might ever need to refactor to a nontrivial
         | getter or setter (whether because you are changing
         | representation or for other reasons), starting with trivial
         | getters/setters instead of fields limits future breakage.
        
         | legerdemain wrote:
         | I had the same question -- why accessor methods instead of
         | making the fields public, but final. If anything, it seems like
         | a layer of indirection.
         | 
         | The only answer that makes any sense is this one from Brian
         | Goetz.[1] Namely, that it's a workaround to support mutable
         | fields of otherwise immutable objects.
         | 
         | To be honest, allowing you to override the methods on an
         | immutable, auto-generated class to inject custom accessor logic
         | feels like an immediate retreat from the conceptual goal of
         | providing an immutable record implementation in the first
         | place.
         | 
         | [1] https://stackoverflow.com/questions/66702223/why-do-java-
         | rec...
        
           | skinkestek wrote:
           | > why accessor methods instead of making the fields public,
           | but final.
           | 
           | The best explanation I have is that it is:
           | 
           | - a convention that seemed like a good idea for many people
           | at the time, it even has a name: Javabeans
           | 
           | - it allows for a standard non magic way to add logic to be
           | run when reading or updating fields
           | 
           | - in a time where source control tools and Java refactoring
           | tools where not as developed as they are today it made sense
           | to make getters and setters everywhere since changing from
           | public fields to accessor methods after it were already in
           | use was probably scary for large teams.
        
             | legerdemain wrote:
             | Thanks for your speculation, but I'd rather take Brian
             | Goetz's word for it. He is, after all, one of the
             | architects of the Java language and the records feature in
             | particular.
             | 
             | ...Unless you're Brian Goetz's alt account?
        
               | skinkestek wrote:
               | > Unless you're Brian Goetz's alt account?
               | 
               | I have a policy of saying whether if is true or false.
               | 
               | That said you should take his word for why it was
               | designed that way and my word as an historical account of
               | why I did that in 2005-2015.
        
       | smoldesu wrote:
       | This might qualify as low-grade threadjacking, so I apologize if
       | this is off topic, but who's actually using Java these days? Most
       | devs I know avoid it like the plague, and only use it to maintain
       | legacy codebases or get CS qualifications. Are there any real
       | advantages to using Java in 2021, besides it's mature
       | community/ecosystem/tooling?
        
         | jeroenhd wrote:
         | The existence of Spring Boot makes Java a very good choice for
         | loads of dev shops. Good balance between features, ease of use,
         | performance and security, not difficult to pick up, and very
         | well documented.
         | 
         | In my personal opinion, C# is a superior language these days
         | now that most of .NET has been ported into dotnet core.
         | However, that's only been the case for a few years and before
         | that, Java was in a league of its own with its excellent
         | library ecosystem and omnipresent JVMs.
         | 
         | Java is a very boring language. Features get added slowly
         | compared to other languages, improvements are generally quite
         | gradual and new concepts only rarely ever get added to the
         | language. This will drive away many hot startups and fresh CS
         | graduates because they want to use the latest technologies in
         | brave new ways and explore the ecosystem.
         | 
         | For general businesses, boring is good. Boring is predictable,
         | understandable and maintainable. Java is not the fastest
         | language to write software in, but it's fast enough not to
         | warrant teaching your staff a new language for. It's missing
         | many features that are standard in other languages, but there's
         | third party libraries to make up for that.
         | 
         | In my mind, languages like Rust and Zig are the Teslas of the
         | software world, exciting, new, full of flaws that need to be
         | ironed out but ready to storm the general market one day soon.
         | Go and Kotlin are the shiny new SUVs, impressive and high
         | quality, but packed with weird design choices and opinions on
         | how to use them. Java and C# are the old van the company has
         | owned for 20 years. Nothing impressive, but reliable,
         | comfortable, predictable, and with quirks that everyone has
         | been learning for years now. Most businesses don't need a
         | Cybertruck, they need to get around, and what businesses
         | already have is good enough for the next while.
        
         | bob1029 wrote:
         | If C# didn't exist, we would certainly be a Java shop. Not only
         | because of the ecosystem & tooling, but also because it is a
         | language that has historically proven its ability to model
         | incredibly complex business domains as well as support mission
         | critical workloads without falling over on itself.
        
           | azth wrote:
           | How's your experience with C#/.NET been? Does it have an
           | analogous offering to Java's JFR[0] for always-on profiling?
           | 
           | [0] https://blogs.oracle.com/javamagazine/java-flight-
           | recorder-a...
        
             | bpicolo wrote:
             | Seems like EventPipe is the C# equivalent?
             | https://docs.microsoft.com/en-
             | us/dotnet/core/diagnostics/eve...
        
               | azth wrote:
               | It seems somewhat similar, but I don't see mention of
               | method traces (similar to a profile view in figure 7 in
               | the blog post I listed).
        
               | bpicolo wrote:
               | There are tools built on top of it to that effect
               | (eventpipe -> dotnet-trace -> tools built on top of
               | trace) https://www.hanselman.com/blog/dotnettrace-for-
               | net-core-trac...
        
             | bob1029 wrote:
             | I am not familiar with the scope of JFR, but there have
             | been some very recent movements around profiling in
             | C#/.NET:
             | 
             | https://devblogs.microsoft.com/dotnet/introducing-dotnet-
             | mon...
             | 
             | https://devblogs.microsoft.com/dotnet/whats-new-in-dotnet-
             | mo...
             | 
             | My experience overall with the C# ecosystem has been
             | fantastic. We started out on .NET Framework 4.x back in
             | 2014-2015, and today are now talking about moving to .NET 6
             | and rewriting our native apps to use MAUI as November grows
             | closer. A lot of the same code we had back in 2015 is still
             | running today with zero modifications.
        
           | switch007 wrote:
           | "historically proven its ability to model incredibly complex
           | business domains"
           | 
           | You surely can't be talking about its type system?
        
             | bob1029 wrote:
             | I certainly prefer the type system of C# over Java, but the
             | latest things I've seen come out of the Java camp give me
             | confidence that I could port most of the same ideas across
             | the way without too much friction if need be.
        
               | switch007 wrote:
               | You said historically, by which I assumed you meant older
               | Java versions, not later ones.
        
         | autodidacticon wrote:
         | It would seem that the world of data engineering is largely
         | dominated by Java.
        
         | throwpupper wrote:
         | Java? Not so much. JVM? Absolutely. The ecosystem, stability
         | and performance is unmatched.
        
         | taftster wrote:
         | Try this list out:
         | 
         | https://projects.apache.org/projects.html?language#Java
         | 
         | There's a LOT of real interest in Java in many many industries.
         | Saying this like "Most devs I know" just really is more of an
         | observation of your local circle.
         | 
         | Big data, Finance, Government
         | 
         | Just to name three really big industries that are dominated by
         | Java.
        
         | lowbloodsugar wrote:
         | >Are there any real advantages to using Java in 2021, besides
         | it's mature community/ecosystem/tooling?
         | 
         | It's fast: C fast in most cases. It can use a lot of cores and
         | memory with minimal effort from developers. It has great tuning
         | parameters for things like GC. We hit a cliff at about 150GB
         | heap, tuned it, and now we're at 300GB. It's "good-enough" type
         | safe. Java grows with you.
        
         | barsonme wrote:
         | Android development. Kotlin is great, but Java is still a
         | perfectly valid choice. In particular, if you don't have
         | dedicated Android developers Java can be a good choice because
         | most people are at least somewhat familiar with it and won't
         | have to learn a new language to be productive. That said, I
         | think anybody who understands Java should be able to understand
         | Kotlin with minimal effort.
        
         | EvilEy3 wrote:
         | > besides it's mature community/ecosystem/tooling?
         | 
         | Not sure if I should be mad or just ignore you.
        
         | skinkestek wrote:
         | > Most devs I know avoid it like the plague, and only use it to
         | maintain legacy codebases or get CS qualifications.
         | 
         | All the customers I have worked with since I became a
         | consultant 4 years ago (and a couple of the best companies I
         | worked with in the decade before) used Java or .Net. More
         | specifically one of them was dotnet core and the rest are JVM.
         | 
         | And I'm happy with that.
         | 
         | Java and Maven means I can focus on the problem and not on all
         | the crazy things people who think they are too clever to use
         | Java do.
         | 
         | I mean I have seen a couple of Abstract Factories in Java, but
         | I haven't seen anyone avoiding putting passwords in the source
         | code by writing things like this:
         | rot13(<rot13password>)
         | 
         | That is stuff I have found in Python code by the one consultant
         | who was to smart to use Java or .Net.
        
         | dboreham wrote:
         | Java has the nice advantage that it works.
        
         | Misdicorl wrote:
         | > besides it's mature community/ecosystem/tooling
         | 
         | Thats the answer. And its a _really_ good one.
         | 
         | The only other languages with the same or better breadth and
         | depth have their own reasons to avoid them like the plague
         | (e.g. C/C++ footguns, difficulty managing large-ish codebases
         | without types)
        
           | villasv wrote:
           | IKR. The question framing is almost like: is there any other
           | reason to use Java except all the most important and good
           | reasons?
        
             | smoldesu wrote:
             | I meant it more on a language level. It has a great network
             | of support, no doubt credited to it's long legacy, but what
             | technical advantages would it provide over writing a
             | program in a language like C++ or Rust? Is it all creature
             | comfort, or does it have some hidden advantage that I can't
             | see?
        
               | Misdicorl wrote:
               | > besides it's mature community/ecosystem/tooling
               | 
               | How could you not see this as an incredible technical
               | advantage in almost any context?
        
               | Misdicorl wrote:
               | If you must have a specific language level technical
               | advantage over C++/Rust, its the incredible GC algorithms
               | available to you while you are (mostly) stuck with simple
               | arena collectors in C++/Rust land.
        
         | haolez wrote:
         | It's a language that protects your investment. There is a lot
         | of effort in backwards compatibility and the language puts a
         | lot of constraints in the devs so that the development moves
         | slowly, but in a sustainable manner.
         | 
         | This is the best case scenario, of course. But it's an argument
         | that I see being used in new Java projects.
        
         | diab0lic wrote:
         | A large chunk of the Netflix backend runs on the JVM. Much of
         | it written in Java. While I agree that many devs avoid it like
         | the plague, and I used to be one of them, once I let go of
         | attachments to programming languages I found it quite a
         | pleasant experience to develop software using Java.
         | 
         | Basically using Lombok and Vavr give you a very nice
         | lightweight functional experience. Bells and whistles tend to
         | be a distraction from making software that works and scales.
         | I'd way rather focus on the hard problems in computing than how
         | to most idiomatically or elegantly express things in a
         | language.
        
       | johnthuss wrote:
       | One of the best things about Records is that they guide you to
       | creating immutable data structures, which Lombok does not. This,
       | along with the reduction of boilerplate, greatly reduces the
       | cognitive load required to understand a lot of code.
        
         | oftenwrong wrote:
         | The guidance is nice, but, unfortunately, Record components can
         | still be mutable. It would be great if there was a way to have
         | a stronger guarantee of immutability.
        
         | chris_j wrote:
         | Lombok has @Value classes, which I use a lot. Is there
         | something about them that does not guide you to creating
         | immutable data structures?
        
           | watwut wrote:
           | Lombok increases the cognitive load required to understand
           | and debug the code.
        
       | EvilEy3 wrote:
       | @JvmRecord data class ...
       | 
       | I'm sorry, you said something?
        
       | jgrant27 wrote:
       | They are still classes, still live on the heap and still need to
       | be garbage collected. Compare with value types that live on the
       | stack in other languages such as Swift, Go and Julia.
        
         | The_rationalist wrote:
         | Value classes, primitive types and specialized generics will be
         | on the stack on the next versions. There is also this related
         | work https://github.com/microsoft/openjdk-
         | proposals/blob/main/sta...
        
         | kasey_junk wrote:
         | I've not explored them much, how well does escape analysis work
         | with them?
        
         | shagie wrote:
         | The heap is an implementation detail.
         | 
         | With escape analysis, the compiler can allocate the data on the
         | heap, stack, or even stick it in registers.
         | 
         | https://www.beyondjava.net/escape-analysis-java
         | 
         | https://shipilev.net/jvm/anatomy-quarks/18-scalar-replacemen...
         | 
         | https://www.javaadvent.com/2020/12/seeing-escape-analysis-wo...
        
           | Someone wrote:
           | Java compilers are getting more and more advanced, but I
           | don't think they will ever become the magical "sufficiently
           | advanced compiler" that produces code that's as good as
           | humans _could_ (but often won't, because of time constraints)
           | write.
           | 
           | I don't think anybody fully disagrees with that. At least, I
           | haven't heard people claim _int_ can be removed from the
           | language because a good compiler can produce identical code
           | for _Integer_ s.
           | 
           | And yes, that can also apply to instances that _do_ escape. A
           | sufficiently advanced compiler could in some /many cases
           | figure out that an array of _Integer_ can be compiled down to
           | an array of _int_. However, it's way easier for a compiler to
           | check a programmer's claim "we won't use features of
           | _Integer_ on these ints" than to deduce that code won't, so a
           | little bit of programmer effort allows for a simpler compiler
           | that can produce faster code.
           | 
           | For me, records and (future) value types are examples of such
           | "little bits of programmer effort"
        
             | eklavya wrote:
             | I could be wrong but I don't think dart has ints, I think
             | it only has objects.
        
               | Someone wrote:
               | https://api.dart.dev/stable/2.6.0/dart-core/int-
               | class.html:
               | 
               | "Classes cannot extend, implement, or mix in int."
               | 
               | https://api.dart.dev/stable/2.6.0/dart-core/num-
               | class.html:
               | 
               | "It is a compile-time error for any type other than int
               | or double to attempt to extend or implement num."
               | 
               | = it seems that, technically, you're right. _int_ is an
               | object in Dart. At the same time, it's a restricted type
               | of object.
               | 
               | So restricted that I think it is aan object only in
               | name/at compile time.
        
           | anonymoushn wrote:
           | Can you have an array of 1 million structs, not pointers to
           | structs?
        
             | im3w1l wrote:
             | 1 million is not a lot. I'd begin by asking myselves "can I
             | afford to chase those pointers?", because maybe you can.
        
               | anonymoushn wrote:
               | No, because my competitors who are attempting to fill the
               | same orders I am attempting to fill are not chasing
               | pointers.
        
               | secondcoming wrote:
               | are your competitors using java?
        
               | jandrese wrote:
               | You are chasing nanoseconds with a garbage collected
               | language?
        
               | jhgb wrote:
               | Those nanoseconds tend to add up.
        
               | Bjartr wrote:
               | That's a good question to ask when faced with a problem
               | that could be solved that way, but a real answer to the
               | question would be useful too.
        
               | [deleted]
        
             | shagie wrote:
             | The first question is "through static analysis, can you
             | guarantee that the structs do not leave the scope?"
             | 
             | The second question to look at is "which JVM are you
             | using?"
             | 
             | Different JVMs may implement this differently. This isn't
             | something that one can say about _Java_. It is something
             | that one _might_ be able to say about HotSpot, Zulu, or
             | GraalVM.
        
               | anonymoushn wrote:
               | It's a global array of structs, let's say.
        
               | shagie wrote:
               | If it's a global, it's very likely allocated on the heap.
               | 
               | The question of "what is the representation of the object
               | on the heap?" then open.
               | 
               | However, the "this is global" complicates it.
               | 
               | This isn't a question for _Java_ to answer. You would
               | need to dig into the specifics of the particular VM that
               | you are using and how it allocates such a structure along
               | with what optimizations it has available.
        
               | iainmerrick wrote:
               | You're technically correct that this stuff is all
               | possible in principle, but the answer in practice right
               | now is "no".
        
               | kelnos wrote:
               | Sure, but I think that's still important that it's
               | possible. And if it doesn't get implemented, the reason
               | may be because JVM developers have done the work to
               | figure out that in the real world the optimization
               | doesn't buy all that much.
               | 
               | Regardless, if you care about performance enough (via
               | actual benchmarks) that you know that you really need
               | some data to be guaranteed to be stack-allocated structs,
               | then you probably shouldn't be using Java (or any GC'd
               | language?) in the first place. Records don't change that
               | calculus.
        
               | shagie wrote:
               | From the link about GraalVM:
               | 
               | > Something that Graal can do that C2 cannot, and a key
               | advantage of GraalVM, is partial escape analysis. Instead
               | of determining a binary value of whether an object
               | escapes the compilation unit or not, this can determine
               | on which branches an object escapes it, and move
               | allocation of the object to only those branches where it
               | escapes.
               | 
               | And from
               | https://docs.oracle.com/en/java/javase/11/vm/java-
               | hotspot-vi...
               | 
               | > The Java HotSpot Server Compiler implements the flow-
               | insensitive escape analysis algorithm described in:
               | 
               | > ...
               | 
               | > After escape analysis, the server compiler eliminates
               | the scalar replaceable object allocations and the
               | associated locks from generated code. The server compiler
               | also eliminates locks for objects that do not globally
               | escape. It does not replace a heap allocation with a
               | stack allocation for objects that do not globally escape.
               | 
               | ----
               | 
               | So, some JVMs implement, others only do a limited subset
               | of the optimizations available with escape analysis.
               | 
               | I would not say that the answer of "is it used in
               | practice" is "no."
        
               | dtech wrote:
               | GraalVM is excellent in performing escape analysis on
               | objects on the call stack, but it does not prevent the
               | pointer overhead that a JVM array-of-heap-object-
               | references has vs an array-of-structs that e.g. .NET
               | supports [2].
               | 
               |  _Theoretically_ it could do hat, but that 's just the
               | classic "sufficient smart compiler" strawman [1]
               | 
               | [1] https://wiki.c2.com/?SufficientlySmartCompiler
               | 
               | [2] https://stackoverflow.com/questions/29665748/memory-
               | allocati...
        
               | shagie wrote:
               | My point wasn't so much "can GraalVM do {some
               | optimization}" but rather that the Java Language
               | Specification doesn't say anything about it and that
               | different JVMs have a different set of optimizations.
               | 
               | So "does Java allocate a record in an array directly as
               | some structure of values in the array or as a pointer to
               | a record object?" isn't one that can be answered by
               | looking at Java.
               | 
               | It _is_ an interesting question, and I 'd be curious to
               | see someone do a deep dive into the internals of GraalVM
               | to show what can be done.
               | 
               | The other part that trickled out in other comments from
               | the person posing the question about the array of
               | records:
               | 
               | > It's a global array of structs, let's say.
               | 
               | and
               | 
               | > No, because my competitors who are attempting to fill
               | the same orders I am attempting to fill are not chasing
               | pointers.
               | 
               | ... which, I'd be curious to see how .NET supports an
               | array of struts (that are presumably changing over the
               | lifetime of the array) that is allocated as a global.
               | That sort of use case and the specifics of how it is
               | implemented could make escape analysis give up and you'll
               | see an array on the heap with pointers to records on the
               | heap as they're passed off to different threads (which
               | each have their own stack).
        
               | dtech wrote:
               | The point is those optimizations are not here now, and
               | haven't been there for the last 25 years. Hand-waving
               | them away as theoretically possible is dishonest. We're
               | 25 years into the most popular programming language's
               | lifetime and the most advanced VM available only recently
               | learned good escape analysis. It isn't easy.
               | 
               | > which, I'd be curious to see how .NET supports an array
               | of struts (that are presumably changing over the lifetime
               | of the array) that is allocated as a global.
               | 
               | Very easy. An array-of-structs (which can still be on the
               | heap mind you) will just be a continuous block of memory.
               | This is totally independent of any locking and
               | synchronization.
               | 
               | For example in a class with 2 32-bit fields, and an array
               | of objects a b object-ref array will look like: [p_ap_b],
               | p being a pointer to [a_0a_1] or [b_0b_1]. A struct-array
               | will look like [a_0a_1b_0b_1].
        
         | [deleted]
        
         | loukrazy wrote:
         | Isn't the point that Record classes will be able to be upgraded
         | to value types easily once Valhalla is done? Or am I missing
         | something
        
           | The_rationalist wrote:
           | No they won't (or maybe they will be able to be speculatively
           | opt-deopt?) Value types above a relatively small size are
           | less efficient than references.
        
           | kasperni wrote:
           | Yes, just add 'primitive' before record in the declaration.
        
       | valenterry wrote:
       | > Actually, records are even better* than tuples. EP 395 says: >
       | > Records can be thought of as nominal tuples.
       | 
       | They are certainly not better, that's just a sad click-bait (the
       | author even admits that).
       | 
       | Sometimes nominal typing is better and sometimes structural
       | typing is better. Forcing people to always use nominal types just
       | ends in a lot of generic or long/meaningless names - one can
       | already see this in Java.
        
         | slver wrote:
         | I've been thinking about structural vs nominal. As you say,
         | both have use cases. How would you combine both in one language
         | so it's not confusing?
        
           | amitport wrote:
           | TypeScript!
        
           | swsieber wrote:
           | Restrict structural types to tuples only.
        
             | slver wrote:
             | That honestly won't be very useful.
        
         | The_rationalist wrote:
         | Nominal ![?] named You can have named tuple members while
         | maintaining structural typing, it's not mutually exclusive.
        
         | kelnos wrote:
         | My general rule (in Scala) is that if I need a tuple larger
         | than two or three elements, I'm better of writing a case class.
         | Tuples get unreadable real fast.
         | 
         | I think tuples are an essential language feature (and it's
         | ridiculous that Java doesn't have them yet), but I think
         | they're often way overused.
        
       | jayd16 wrote:
       | Records are good but if you want this in Lombok don't you just
       | use @Getter instead of @Data to generate read only methods?
       | 
       | Serialization is handled by Java bean getters and setters just
       | fine. I don't really see an advantage.
        
         | simonpantzare wrote:
         | I've used @Value along with @Builder(toBuilder=true).
        
       | ctvo wrote:
       | Who is arguing otherwise? It's assumed that when a language adds
       | a new feature that's historically been provided by libraries,
       | it's probably better optimized. CompletableFutures, Streams,
       | Date/Time. For many they've replaced libraries filling the gaps.
       | 
       | But not all of us can use JDK 14, and will continue to use Lombok
       | if we're writing in Java.
        
         | Rapzid wrote:
         | Work on a Grails app; only boots on up to 11 ATM. BUT, the hot
         | reload only works with 8... So while the app runs on 11, most
         | development occurs on 8 still.
         | 
         | Lombok JustWorks(tm). You forget it's there until you setup a
         | new dev environment and forget to setup the annotation
         | processor in IntelliJ.
        
       | pkulak wrote:
       | So what's the answer to the question? Pattern matching and
       | destructuring? But I don't see any reason Kotlin data classes
       | can't do that. I know Kotlin pattern matching is pretty lack-
       | luster, but I never thought this was the reason.
        
       | abductee_hg wrote:
       | sorry -java .. better? what? why would anyone use java for
       | anything? let me give an example: from a project a while(some
       | years actually) ago i still have a license for a php-ide(zend).
       | its in java. no chance in hell to get it working today.
       | 
       | meanwhile, stuff i did 2003 still runs on windows out of the box,
       | even in wine/osx. so again: why use java for anything?
       | https://twitter.com/abductee_org/status/711966430133026816 (try
       | it https://www.pouet.net/prod.php?which=11247 )
       | 
       | oh and there is this:
       | https://people.eecs.berkeley.edu/~wkahan/JAVAhurt.pdf so, double-
       | again: why use java for anything?
        
       | AtNightWeCode wrote:
       | Not sure why immutable data structures have surfaced as something
       | important. Typically you never change fields so it is kind of
       | only of academic value if a field in a POD, POJO, POCO or
       | whatever it is called in the specific language actually may
       | change.
        
         | ramblerman wrote:
         | > so it is kind of only of academic value if a field in a POD,
         | POJO, POCO or whatever it is called in the specific language
         | actually may change.
         | 
         | I'm not sure if you've debugged much, or inherited any large
         | legacy projects, but knowing it is immutable vs "typically it
         | isn't" is a pretty big distinction in that moment.
        
           | AtNightWeCode wrote:
           | Good code don't have this issue.
        
             | slver wrote:
             | Good code doesn't have concepts like "typically doesn't
             | mutate". It's either mutable or immutable.
        
               | AtNightWeCode wrote:
               | The standard way to do it is to mutate clones as always
               | in Java. Typically by use of libraries that provide this.
               | You really need very bad code to have to think about if
               | objects are mutable.
        
               | slver wrote:
               | Apparently you don't know most immutable structures are
               | optimized for modified cloning in ways mutables aren't.
        
               | AtNightWeCode wrote:
               | This is Java.
        
         | razzm256 wrote:
         | There are many good things enabled by immutability, like
         | safer/easier multithreading, value-like semantics for objects.
         | It is _definitely_ not only of academic value.
        
           | AtNightWeCode wrote:
           | Typically you use values and not objects for these kind of
           | things so not that much gained.
        
         | the_af wrote:
         | "Typically" this means you can never be sure, which is a
         | problem.
        
           | AtNightWeCode wrote:
           | Sure of what? If your code is not garbage it takes two
           | seconds to see where things change. It should be very places
           | in the code.
        
             | slver wrote:
             | It takes two seconds in a hello world demo. It takes
             | probably more in a millions of lines project.
        
               | AtNightWeCode wrote:
               | Fields of an object should typically not change. But yes,
               | I had to make a field of a class immutable some time ago.
               | There was a bug and I could not read the code to figure
               | out were the object was changed. Still, caused by bad
               | code. Same object sent around pretty much everywhere.
        
               | slver wrote:
               | So even you, the master of great code, wrote bad code. I
               | guess immutability is worth something then.
        
               | AtNightWeCode wrote:
               | I did not write the original solution...
        
               | the_af wrote:
               | Precisely: you did not write the original solution, which
               | is where immutability shines. It's a code comprehension
               | tool; it gives you guarantees about code _you_ didn 't
               | write. That's a huge boon!
        
               | AtNightWeCode wrote:
               | There are no guarantees that it is the same object you
               | get so it is pointless.
        
               | slver wrote:
               | So you reckon we only need immutability if two or more
               | people have to work on code. Ok.
        
               | AtNightWeCode wrote:
               | You are just too stupid. I hope you are not immutable.
        
         | reom_tobit wrote:
         | Keyword being "may".
         | 
         | Guarantees are nice. Especially if objects are going to be
         | passed around every which way from Sunday. It allows you to
         | better reason about what could happen, and where.
         | 
         | Java has taken a while to get there, but I'm glad that they
         | have finally.
        
           | AtNightWeCode wrote:
           | Well, if you pass around objects and change their state
           | records will not help. People who does this are already using
           | immutable frameworks in Java to clone and change some field
           | and then pass it along.
        
             | reom_tobit wrote:
             | Sure, things have been bolted on top of Java to allow this
             | to happen. People have made use of them.
             | 
             | Java now has built in support for these things, so no
             | longer will developers rely on third-party solutions.
             | 
             | This is great for the Java world, and for any languages
             | that are being built on top of the JVM by extension.
             | 
             | I would politely disagree with your characterisation of it
             | being just academic, as an engineer I find it incredibly
             | exciting. Admittedly, my bar is pretty low for excitement
             | these days.
        
               | AtNightWeCode wrote:
               | I have done Java for 25 years and never felt any need for
               | records. There are so many issues...
        
       | jsd1982 wrote:
       | Using Dark Reader extension for Chrome, all of the sample code
       | text goes to the same color as the background so I thought I was
       | scrolling over huge chunks of blank space.
        
         | tut-urut-utut wrote:
         | It's not blog authors responsibility to test his blog for all
         | possible extension that some readers might be using.
         | 
         | If the reader is using some third-party software that modifies
         | the original blog design, it's his responsibility to disable it
         | if it doesn't work seamlessly.
        
           | [deleted]
        
           | knoebber wrote:
           | I agree with this in general, though sometimes
           | incompatibility with popular extensions is an indication that
           | the author isn't following standards.
        
             | tomc1985 wrote:
             | Asking people to test against all the combinations of
             | browsers _and_ extensions? That 's asking _a lot_
        
         | capitainenemo wrote:
         | I was surprised to encounter this as well in Firefox using Dark
         | Mode. I'm still not 100% sure what's going on, because it's
         | rather odd, but if I inspect the page, and add a: .language-
         | java { opacity: 0.99999 } All content instantly renders.
         | Interestingly: .language-java { opacity: 1 } or .language-java
         | { opacity: 0.99999999 } /* probably same as 1 */
         | 
         | Blanks out the content again. Seems rather odd behaviour to me
         | so definitely interested if anyone figures it out, even if this
         | is kind of derailing the discussion.
        
           | capitainenemo wrote:
           | Kay. Day got a bit more quiet. I vaguely remembered running
           | into this weirdness before. It's 'cause apparently opacity
           | creates a new stacking context. Doing z-index:1;position:
           | relative; does same thing. The rule that seems to be breaking
           | everything is the one that forces a default opaque background
           | on everything with dark text. For it to break this, there
           | must be overlapping content, but haven't found it yet. But
           | enough to know what was going on..
        
       | billyjobob wrote:
       | Kotlin data classes can use Java records as their implementation
       | if running on JVM, so it's not like you have to choose one or the
       | other.
       | 
       | https://kotlinlang.org/docs/jvm-records.html#declare-records...
        
         | _old_dude_ wrote:
         | I wonder why, unlike a Java record, in Kotlin a data class
         | annotated with @Record can not be local.
         | 
         | Being able to use local records is a useful feature in
         | particular in unit tests.                 @Test       void
         | testPoints() {          record Point(int x, int y) {}
         | ...       }
        
         | crdrost wrote:
         | This is great news!
         | 
         | I was also kind of surprised to see the article talking about
         | algebraic data types... table stakes for ADTs is sum types and
         | I have missed them considerably in the Java ecosystem.
         | 
         | Kotlin has something like them with sealed classes, although
         | I'm a newcomer to the Kotlin and Spring Boot ecosystem so I
         | don't see explicitly how I make some simple case like JSON
         | {"type": "left", "abc": 123}         {"type": "right", "def":
         | "456"}
         | 
         | turn into some structure like:                   sealed class
         | EitherTest {             data class Left(val abc: Long):
         | EitherTest()             data class Right(val def: String):
         | EitherTest()         }
         | 
         | rather than the hacky version that you have to do in relational
         | databases and Java which don't support such things,
         | enum class EitherType { LEFT, RIGHT }         data class
         | EitherTest(val type: EitherType, val abc: Int?, val def:
         | String?)
         | 
         | Like I'm not saying that there's _no way_ , I'm sure there's a
         | way... just that the ecosystem seems so hesitant to embrace sum
         | types that like the above sealed class is widely viewed as a
         | hack and there is no statement about "here is how you actually
         | use sum types for everything in your Spring application with
         | Kotlin."
         | 
         | Was gonna give the choose-your-own-adventure example of why sum
         | types are handy and how you have to kind of hack around them
         | with inheritance when you don't have them but it occurs to me
         | that anyone who has stuck with this comment this far probably
         | already has some familiarity with this?
        
           | TJSomething wrote:
           | In traditional Java, you're probably using Jackson for your
           | JSON. You can achieve those sorts of results by specifying
           | the classes and type tags in annotations on an abstract
           | Either class to use Jackson's polymorphic serialization
           | feature.
        
             | balefrost wrote:
             | The point of sealed classes is that you have a known number
             | of possible representations. So you can have `when` blocks
             | that exhaustively check all possibilities. Having an open
             | class hierarchy would not work for that purpose.
        
           | oftenwrong wrote:
           | Sealed classes are (most likely) going to be in the next
           | version of Java, Java 17: https://openjdk.java.net/jeps/409
        
       | The_rationalist wrote:
       | Kotlin data classes can be used with the JPA contrary to Java
       | records. It's good to encourage immutability, but it is often a
       | misfit and isn't the role of a "data class", they could have
       | added a separate class qualifier immutable that would have been a
       | better separation of concerns, here it's ad-hoc. Kotlin is
       | enabling such immutable support thanks to Java records ironically
       | https://kotlinlang.org/docs/jvm-records.html#declare-records...
       | 
       | Note however that an upcoming version of Java will get first
       | class ergonomic support for manipulating immutable data:
       | https://github.com/openjdk/amber-docs/blob/master/eg-drafts/...
       | 
       | There is also https://github.com/hrldcpr/pcollections
        
         | hueho wrote:
         | > Kotlin data classes can be used with the JPA contrary to Java
         | records.
         | 
         | Arguably this is more of an issue of JPA than an strict
         | advantage of Kotlin: JPA was designed at a time where the
         | general consensus was to primarily use mutable data, and was
         | heavily influenced not only by existing Java ORM APIs, but by
         | their implementations.
         | 
         | Kotlin itself supports JPA by the use of a compiler plugin,
         | which is a good enough solution, but nevertheless, not one
         | native to the language. Data classes mostly work by accident,
         | but pretty much any documentation you will find points it to
         | _not_ use them with JPA.
        
         | vips7L wrote:
         | I'm really not sure if using data classes with JPA is smart
         | idea. Solely because of generated hashCode/equals and JPA lazy
         | loading. For instance ebean recommends against it [0].
         | 
         | https://ebean.io/docs/best-practice/#kotlin-data-class
        
         | Bjartr wrote:
         | > Kotlin is enabling such immutable support thanks to Java
         | records ironically
         | 
         | That a member of the JVM ecosystem is leveraging new JVM
         | capabilities isn't ironic, it's totally expected.
        
       | rdsubhas wrote:
       | I believe the article focuses too much on "perceived/future"
       | benefits of records, while ignoring the actual benefits that
       | Lombok & Kotlin data classes provide today.
       | 
       | For example, article does not mention lombok @Builder and Kotlin
       | `copy` when talking about boilerplate. Boilerplate is not just
       | about application code, it's also about test code!
       | 
       | We have dozens of entities, and when unit testing them - always
       | having to construct the COMPLETE record with all attributes from
       | scratch is a pain. Nested records things worse. We now have all
       | data classes as @Value+@Builder, and test factories provide
       | consistent builders which the actual test cases can chain,
       | override and use. This is possible in Lombok & Kotlin, but not in
       | Record.
        
         | MichaelMoser123 wrote:
         | yes, java records are part of jdk14, many places are still
         | stuck with jdk8 or jdk11, hoewever everyone can use lombok
         | (they didn't mention that detail in the article)
        
       | valenterry wrote:
       | Scala's case classes are missing in the comparison (only
       | mentioned briefly at the very end). They offer everything that
       | records do and more. Good to see that Java finally catches up a
       | bit.
        
         | pron wrote:
         | I don't think they offer more. Deconstructing patterns and
         | "reconstructors" (generalised "withers") are on the way. And
         | Java features are often designed as a complete whole: some of
         | the feature is in the language, some in the core libraries, and
         | some, even, in the VM. In the case of records, they're treated
         | in a special way by the runtime (e.g. in serialisation).
        
         | halfmatthalfcat wrote:
         | Scala is usually omitted for one reason or another when Kotlin
         | is compared against Java as a better alternative, which is a
         | shame.
        
           | aero142 wrote:
           | Scala has to the solution to every problem except the problem
           | of too many features.
        
             | AzzieElbab wrote:
             | Maybe but scalas case classes are super easy to grasp and
             | require no magic like annotations
        
               | xenomachina wrote:
               | What annotations are you referring to?
        
               | scubbo wrote:
               | I'm not the person you were asking, but, presumably,
               | Lombok's annotations.
        
               | AzzieElbab wrote:
               | Lomboks. Seriously, scala case classes are like the very
               | first thing people start using when learning the
               | language. Scala3 enums are even more straightforward
        
               | xenomachina wrote:
               | The ancestors of your comment mention Kotlin, not Lombok,
               | which is why I asked. Kotlin's data classes are probably
               | the analog to Scala's case classes, and they do not
               | require annotations.
        
             | ernst_klim wrote:
             | > except the problem of too many features
             | 
             | Scala is a pretty simple, concise and coherent language
             | though. Never understood why people deem it has too many
             | features, I write it professionally and never felt so.
             | 
             | At least comparing it to C, C++, Python. Java may be more
             | simple, but you have tons of features added with
             | metaprogramming via dozens of annotations generating lots
             | and lots of boilerplate, Lombok and Spring are examples of
             | that.
        
               | kerblang wrote:
               | > Never understood why people deem it has too many
               | features
               | 
               | I'll start with one (key)word: `implicit`
               | 
               | I agree with your distaste for metaprogramming though.
        
               | halfmatthalfcat wrote:
               | You can use Scala without introducing implicits and even
               | if you have to interopt with a library that does require
               | them, it's quite easy to learn how to use them. It's also
               | easy to abuse them but then that's not really Scala's
               | problem.
               | 
               | They are changing implicits in Scala 3 though with the
               | "given" keyword which is more ergonomic.
        
               | cutler wrote:
               | Scala can't let go of implicits as they're a fundamental
               | part of the language. I just don't believe this Scala 3
               | fudge to give the impression implicits are not alive and
               | well beneath the surface.
        
               | asimpletune wrote:
               | You don't have to use implicits though, but you'd be
               | super happy they're there should you ever be in a
               | situation where they're helpful
        
               | diroussel wrote:
               | Doesn't a monad or for comprehension use implicits to
               | find the right CanBuildFrom?
               | 
               | Are you suggesting to use scala without using for
               | comprehensions? Or do you mean you don't need to write
               | your own?
               | 
               | It's been a long time since I wrote scala, so may be
               | getting it wrong.
        
               | ernst_klim wrote:
               | > I'll start with one (key)word: `implicit`
               | 
               | I don't think implicit counts as "too many features" or
               | as something complex. Basically all it does is finding a
               | canonical value in scope for a hole of certain type.
        
               | kjeetgill wrote:
               | I only worked in Scala briefly so maybe it's coming from
               | Java habits, but implicits were huge pain. When first
               | reading through code you don't really know if that
               | function call you eyed over really has the params you
               | think it does. It makes it WAY harder to track what's
               | derived from what.
               | 
               | Either way, the local Scala guru there said the Scala
               | community was starting to get over implicits.
        
           | adambatkin wrote:
           | Lombok and Kotlin are both much easier to integrate into
           | existing Java applications and libraries than Scala.
        
             | krzyk wrote:
             | Lombok is the problem not a solution (see
             | https://github.com/projectlombok/lombok/issues/2681
             | regarding support for JDK 16 to understand why) and a
             | ticking time bomb in every project that wants to move past
             | JDK 15/16.
             | 
             | But why do you think Kotlin is easier to integrate than
             | Scala? Both work on JVM.
        
             | kelnos wrote:
             | I don't see how Kotlin is easier to integrate into an
             | existing Java app than Scala is. They both require adding
             | new dependencies and changing your project build config,
             | and require developers who know the respective new
             | language. That's... about it. They both offer similar
             | levels of interop with Java libraries.
             | 
             | If you want to assert that finding Kotlin developers is
             | easier or that Kotlin is an easier language to learn, sure,
             | that might be the case (I really don't know), but that's
             | not really an integration task.
        
               | throwpupper wrote:
               | What about the fact that Kotlin collections are fully
               | interoperable with Java collection? That makes the
               | transition significantly easier.
        
               | halfmatthalfcat wrote:
               | I believe Scala's are as well, this seems to be a pretty
               | complete list:
               | 
               | https://www.scala-
               | lang.org/api/2.13.5/scala/jdk/javaapi/Coll...
        
               | balefrost wrote:
               | Kotlin's STDLIB collection types are essentially aliases
               | for the Java types. So while the Scala adapters are low-
               | cost, in Kotlin everything's zero-cost.
               | 
               | One other benefit of that is you maintain object
               | identity. I don't think that Scala's wrappers do that.
        
               | darksaints wrote:
               | Scala has the full suite of Java collections without any
               | conversion or overhead whatsoever.
               | 
               | But it also has Scala collections. With scala collections
               | you get the full power of the Scala type system, as well
               | as a much richer and full featured collections api. So
               | most scala programmers won't bother with java collections
               | unless they have specific java interop requirements.
               | 
               | The Scala adapters are merely ways of converting java
               | collections to scala collections and vice versa.
        
         | mumblemumble wrote:
         | I think that case classes are roughly equivalent to Kotlin data
         | classes for the purposes of this comparison. In particular, one
         | of the extra features they offer is the ability to make fields
         | mutable. Which, in some cases, may be useful, but also means
         | that they aren't, strictly speaking, _transparent carriers of
         | immutable data_.
        
       | throwpupper wrote:
       | I think the article is misleading in the list of advantages over
       | Kotlin's Data Classes.
       | 
       | 1. Destructuring - available in Kotlin
       | 
       | 2. Copy with change - available in Kotlin
       | 
       | 3. Serialization - not sure why Kotlin data class would not be
       | serializable
       | 
       | 4. Boilerplate - Kotlin takes care of equals and hashCode
       | 
       | Huge disadvantage that matters to me is that record fields cannot
       | be mutated. It makes the records much less useful.
        
         | throwaway4good wrote:
         | "Huge disadvantage that matters to me is that record fields
         | cannot be mutated. It makes the records much less useful."
         | 
         | No. It makes them much more useful.
        
           | throwpupper wrote:
           | Well it means that the second you need a setter you can't use
           | records so all the boilerplate remains.
        
             | zaphar wrote:
             | Why would you need a setter for a data class? They add no
             | value there.
        
               | [deleted]
        
             | valenterry wrote:
             | You are supposed to create a new copy with some of the
             | fields changed. Just like you do it with the java.time.*
             | classes and others.
        
               | bcrosby95 wrote:
               | Yet the only mechanism for this is error prone or relying
               | on mountains of boilerplate.
        
               | vbezhenar wrote:
               | Instead of changing few bytes, now I have to copy
               | hundreds of bytes around and add more stuff for GC to
               | collect.
               | 
               | Well, they have to obey Wirth's law, I guess.
        
               | kaba0 wrote:
               | Or you know, the JIT will trivially optimize away the old
               | class if it is reassigned to the same variable, as you
               | would use it inside a loop. How do you think the litany
               | of FP languages work? Like Haskell, Scala, Clojure?
        
               | vbezhenar wrote:
               | That's a theory not happening in practice. In practice
               | Java programs are slow and memory-hungry because of those
               | issues when some people think that it's cheap to create
               | small objects or that escape analysis will solve their
               | issues without verifying that it works for their case.
        
               | kaba0 wrote:
               | Most of the world's server applications would like to
               | disagree with you.
        
               | slver wrote:
               | Java isn't perfect. But you underestimate the amount of
               | software written in it. Or even things like Python and JS
               | which are a lot more basic but have similar elements in
               | regards to their memory model. What do you use?
        
               | vbezhenar wrote:
               | I work as Java developer for the last 10 years, I
               | perfectly understand the amount of software and other
               | things.
               | 
               | I don't know much about Python and JS, but I do know that
               | they're not using immutable model, everything is mutable
               | in Python and in JS, so I'm not sure what's your point.
               | The only immutable language I'm aware of is Haskell which
               | is not used widely. Just because JVM is faster than
               | Python or V8 does not mean that it's OK to slow it down
               | with immutables.
        
               | slver wrote:
               | Using immutables doesn't mean you go full Haskell.
               | Strings are also immutable you know.
        
               | slver wrote:
               | It can be done in theory, but the JVM does nothing of the
               | sort right now.
        
               | kaba0 wrote:
               | False. The JVM already does quite a good job with escape
               | analysis, and record types just add extra semantic
               | information to potentially further improve the situation.
        
               | slver wrote:
               | What precisely of what I said is "false"?
        
               | kaba0 wrote:
               | the JVM does _something_ of the sort right now.
        
               | slver wrote:
               | Every time you rebuild a record you run through its
               | constructor. I doubt this can be optimized the same as
               | with a plain C struct.
               | 
               | Eventually with some more evolution. But not yet.
        
               | jandrese wrote:
               | Counterpoint: Java programs with memory consumption
               | graphs that have decided sharktooth patterns, which is
               | extremely common.
        
               | kaba0 wrote:
               | As opposed to what exactly? How would a C program's
               | memory graph look with quick bursts of memory-allocation
               | requiring functionality, especially if it is very dynamic
               | in nature? Yeah you can overallocate with memory pools
               | and the like, and there are cases of course where escape
               | analysis can't help -- that's why Valhalla is in the
               | works for quite some times now.
               | 
               | But GC-wise the JVM is far ahead the game, whatever you
               | see is likely better than the same functionality would be
               | under JS, Python, C#, Go, etc (though the latter two do
               | have value types/structs already so they can at some
               | place manually do the "escape-analysis". But not every
               | problem requires/can use value types either)
        
               | kelnos wrote:
               | I don't know if the JVM developers have actually
               | implemented this, but since records are immutable,
               | there's no reason why a copy couldn't share memory
               | between the instances.
               | 
               | The major downside is that could ruin cache locality and
               | make passing the instance across a FFI boundary require a
               | copy.
               | 
               | Another optimization would be that the JIT (or even
               | perhaps javac) could notice cases where you make a copy
               | (with one field changed) of a record and then never use
               | the original reference again. If the JIT (or javac) can
               | prove that no other bit of code holds a reference to the
               | original record, it can reuse and mutate the original one
               | instead of making a copy. I don't know if this
               | optimization is or will be implemented, of course.
               | 
               | Either way, I expect the overhead you mention ends up
               | being worth the benefits of immutable data. (That's been
               | my experience using Scala, anyway.)
        
               | JackFr wrote:
               | You have to copy less than you think. Because the data is
               | immutable, you can share everything but the changed
               | fields.
        
               | The_rationalist wrote:
               | Then you've invented mutability without
               | references/identity. Except those are desired properties
               | for data classes, unlike for value classes which have
               | such semantic difference.
               | 
               | Btw Kotlin allow to make immutable Java records too so
               | clear winner.
        
               | pkulak wrote:
               | Not sure what you're getting at. Immutable means exactly
               | that. If you hand out an object, then do a copy change,
               | that change isn't reflected in the object you gave to
               | another method/thread/fiber/etc. Immutability doesn't
               | mean application state never changes; it means that a
               | single reference will always point to memory that hasn't
               | changed.
        
               | the_gipsy wrote:
               | You write java and worry about bytes copied?
        
               | vbezhenar wrote:
               | Yes, I do. Java could be quite fast if you won't slow it
               | down on purpose.
        
               | marcinzm wrote:
               | I mean, you do realize that you're writing Java code
               | right? If you want ultimate low level optimization and
               | control then you're already about ten miles too far
               | downstream to make that turn. Also, I'm guessing the copy
               | overhead is more than offset by the JVM being able to do
               | better optimizations around these data structures.
        
               | iainmerrick wrote:
               | Structs with mutable fields is hardly "ultimate low level
               | optimization", it's something a lot of programmers still
               | use as a matter of course. (I say this as a fan of
               | immutable data!)
               | 
               | Ultimate low-level optimization in Java would be more
               | like packing your structure into arrays of integers -
               | which is something _people actually do_ in Java. Just
               | because you're using Java doesn't mean you don't want
               | your code to run as fast as possible.
        
               | davewritescode wrote:
               | This has been argued ad nauseam around the time Scala
               | started gaining traction because scala's collections are
               | grouped into immutable and mutable. The consensus at the
               | time is that the GC overhead is well worth the ability to
               | parallelize computation.
        
               | krzyk wrote:
               | GC is there for a reason, unless you do HFT, use it to
               | your advantage.
        
       ___________________________________________________________________
       (page generated 2021-05-07 23:02 UTC)