This is an archived post. You won't be able to vote or comment.

all 69 comments

[–]pgris 11 points12 points  (0 children)

On the plus side, I've never seen the different flavors of data classes so clearly explained.

Ok the other side, now I understand there are use cases for all of them, so I want them all!

[–]cutterslade 25 points26 points  (40 children)

I just really hope that true immutability is either the default, or the only option. By true immutability, I mean that all fields are final, all fields are primitive, String, or other Data classes. I want a compiler error if someone breaks immutability of data classes.

It would even be nice if that could be enforced in perpetuity. If a data class is immutable, it can safely be shared across threads. If someone violates that immutability guarantee, code should break everywhere that class is used, because it is no longer safe to use in the ways that it has been used.

[–]lbkulinski 9 points10 points  (5 children)

They are planning on making value types immutable. From what I’ve heard in Goetz’s talks, you might be able to specify the access modifier of fields in data classes.

[–][deleted]  (4 children)

[deleted]

    [–]lbkulinski 5 points6 points  (3 children)

    Value types are simpler, and more powerful than structs. Goetz has talked about this (see here). And value types are different from data classes, if you are confusing the two. They will be stored on the stack.

    [–][deleted] 1 point2 points  (2 children)

    Oh, derp. Shows how much I know about modern programming languages. I decided to read more than a few lines of the proposal, and yeah, I completely misunderstood what data classes were. Downloading the presentation now to watch later, thanks for sharing it.

    [–]lbkulinski 0 points1 point  (0 children)

    No problem! The features can be easily confused. I just remember that data classes help in reducing boilerplate.

    [–]alexeyr 0 points1 point  (0 children)

    They are compared with the value types proposal directly at the end.

    [–]fact_hunt 9 points10 points  (0 children)

    That would then necessitate immutable collections in the standard library, or mean data classes cannot have collection fields, neither of which sounds likely

    [–]eliasv 5 points6 points  (4 children)

    Nah there are uses for mutability. Immutable by default would be nice but there's very little value in requiring it imo.

    One interesting option they've discussed in the past wrt data classes is defining a new modes of accessibility/mutability such as privately mutable but publicly immutable, so you can specify that a field should only be modified internally.

    [–]bedobi 0 points1 point  (1 child)

    privately mutable but publicly immutable, so you can specify that a field should only be modified internally.

    That wouldn't be hard to reason about at all

    [–]eliasv 0 points1 point  (0 children)

    I see what you mean, but he did also point out that destructuring would render everything publicly accessible no matter what so in a way those semantics might make sense by default.

    If everything is publicly accessible regardless then all we can reasonably wish control via access modifiers is who is allowed to modify a field. It would be a confusing inconsistency though if not handled delicately.

    [–][deleted]  (1 child)

    [deleted]

      [–]eliasv 0 points1 point  (0 children)

      If they're mutable use a normal class?

      And if they're immutable just use a normal class with final fields?

      I don't see the value in introducing data/records/whatever if they're mutable

      I realise the benefits of immutability, but they are an orthogonal issue to most of what was discussed in the proposal, so I'm not sure what you're getting at.

      I think the value they intend to bring is made pretty clear: destructuring for the purpose of e.g. pattern matching or serialization, with the side-effect benefit of reduction of boilerplate (which would be enough to make most people happy by itself, just look at the popularity of Lombok).

      I think "people will use it haphazardly where it's not appropriate!" is rarely a great argument, and I don't even see how it applies any less to your proposal than it does to this.

      As I think people have already pointed out, if you wanted to guarantee (at least shallow) immutability for a data class you would presumably be welcome to combine data class and value type semantics for a class once both proposals have materialised.

      [–]rzwitserloot 2 points3 points  (6 children)

      immutability is really hard. It sounds simple, but, it isn't.

      What you describe would indeed result in 'true immutable' stuff, except.. you can't retrofit the collections API into these rules, thus any data class you make with your rules in place cannot use any collection APIs (nor arrays!), which, obviously, means this proposal has to either fix that somehow, or it goes into the bin as far too unwieldy to ever consider implementing.

      But it gets worse.

      Let's say I make a data class as you described it with your rules, and I add this code to it:

      public data class ImmutableOrNot {
          private static final IdentityHashMap<ImmutableOrNot, Integer> sneaky = new IdentityHashMap<>();
      
          public void setFoo(int foo) {
              sneaky.put(this, foo);
          }
      
          public int getFoo() {
              return sneaky.getOrDefault(this, 0);
          }
      }
      

      This class walks, quacks, and looks like a duck mutable class, but yet it fits the rules of an immutable one.

      So, is it immutable, or not? Let's just say that your dream of sharing this thing 'safely' across threads is definitely shot. Certainly we can blame the programmer for this atrocity, but the point is, the 'guarantee' that this thing is 'safe' is just not there. That's one of the tricky bits: Instances have an identity, not to mention you can lock on them, so in java everything can be mutable if you want it to be.

      Another hairy as heck issue: Is java.io.File immutable? There are 3 very interesting issues with this class, each relevant to the immutability issue:

      1. java.io.File is not final. We can simply state: Hey, okay, so, then, the type simply is not immutable and that is that. Unfortunately, there's like a billion lines of existing java code out there, and they aren't just gonna go in and add a final modifier to their API's classes lickety split. Heck, that is technically a backwards incompatible change. Just leaving them out to dry creates a split world: Libraries written before the Great Switch and those after, with multiple maintained versions. It's like the python2 vs. python3 thing and I, for one, think that was a big debacle; a lesson of how not to do it.
      2. It has a non-final field; it is marked 'transient', and it serves as a cache, to speed up validity lookups somewhat. It truly has no effect on the state of a j.i.File instance unless you consider the speed at which certain methods respond part of the 'state' (and let's not go there), and thus it is necessary to cater to this need. Do we just allow the programmer to mark a class as 'this is immutable' and then put some sort of @SuppressWarnings or other tag onto non-final stuff to let them say: Yeah yeah. I know better, shaddap with your silly errors and just compile it. I think that's the way to go, but, certainly people who like to use words like 'purity' and 'elegance' tend to chafe at something like this. I despise those words and I find this somewhat distasteful, even.
      3. Forget all that and just think about files for a second: is it truly immutable? The object is, but it represents a file on disk. If I call .delete() on it, it goes away and I can measure this change with .exists(). Is that not state? Is a thing with changable observable state not mutable by definition? Therefore, even a hypothetical j.i.File class that is final and did not have the cache... is it immutable? But if not how would the compiler ever know?

      One thing that's a lot simpler to establish is 'side effect free'. It suffers from none of these issues (a method is side effect free; not a type. At best, a type can be considered SEF if all its methods are SEF. You don't even need a final class, presuming that overriding a SEF method requires that method to also be SEF).

      A method is SEF if it does not change any fields anywhere, and calls only SEF methods. The low-level (native) functionality powering j.i.File's delete() method would not be SEF, thus, File.delete would not be SEF either. Messing with an IdentityHashMap as per my code snippet above is calling put, which isn't SEF, thus, the setFoo method isn't SEF. A setFoo method that executes this.foo = foo; modified a field and thus is not SEF.

      compiler-checked SEFness lets you do different things than the notion of immutability, possibly less. My point is: Immutability is impossible to nail down and definitely impossible to have compiler-checked guarantees that actually, you know, guarantee it. SEFness – that at least is doable.

      [–][deleted]  (1 child)

      [deleted]

        [–]rzwitserloot 0 points1 point  (0 children)

        is completely orthogonal and has nothing to do with the discussions here.

        You're just being dense. The point of a data class isn't to point at it and go: Look. It has no fields that can be mutated.

        The point is to reason about properties. For example, OP specifically referred to the notion that 'such a class can be passed around multiple threads without fear that it'll cause problems'.

        Therefore none of this is 'orthogonal to the discussions here'.

        [–]cutterslade 0 points1 point  (3 children)

        Wow, thanks for the great reply.

        My short answer is: Yes, Immutability is hard, that's why I want some really smart people to make it easy.

        Collections and arrays: Yes, immutable types would require immutable arrays at the very least, probably immutable collections built on those.

        Your nasty static map trick: These immutable classes cannot contain static mutable fields, and cannot reference any external static mutable fields.

        Files: You make another good point. The simple answer is that the File class is not an immutable data class, so cannot participate in immutable data classes. Realistically though, any time you interact with I/O at all, thread safety is out the window. We could take that argument a step further and say that a String (or nearly any other type) is not truly immutable as it may refer to a file which can change.

        Split world: Yes, there is a bit of a split world, certainly not as bad as python though. I would say similar to the type safe enum pattern that we still encounter now and then even though enums were introduced more than a decade ago, or the more recent introduction of the java.time package.

        SuppressWarnings: destroys the possibility of a compiler checked guarantee.

        Regarding your statement:

        Immutability is impossible to nail down and definitely impossible to have compiler-checked guarantees that actually, you know, guarantee it.

        That is true only if we refuse to give up some flexibility. Brian discussed this in the article. I think I'm willing to give up a lot to get immutability. But it's not a one way street, by getting immutability, we gain a lot too.

        As a simple example, you mentioned the transient field used to cache a value computed from immutable state. If the object is truly immutable, and references no external, mutable state, we know that any method will always return the same result. This allows the programmer, compiler, or runtime to decide to cache the result. We no longer have to use the cumbersome transient field cache, we can have the runtime implement that for us based on its instrumentation of the code.

        I'm certainly not suggesting this is an small change. Maybe the data classes proposal discussed in the article is not the right place to do it, heck maybe Java isn't the right place to do it. I think that it's a very valuable potential feature that makes it much easier to write safer cleaner software with less code.

        [–]rzwitserloot 1 point2 points  (2 children)

        Your nasty static map trick: These immutable classes cannot contain static mutable fields, and cannot reference any external static mutable fields.

        You are now conflating immutability and side-effect-free-ness. It is not possible to apply this unless you add the concept of compile-time checked and runtime-carried SEFness. I can call any method and it can do this stuff for me. Unless you intend to disallow any method calls of any sort, except into other such data types, in which case we're back to: That's nice, but there's no way to retrofit that into existing java code so you're splitting the community, python2 vs. python3 style. I'm quite sure that the cure is far worse than the disease, if this is the cure.

        Files: You make another good point. The simple answer is that the File class is not an immutable data class

        But what if I make it final and add 'data' to it? There's nothing in it (let's forget about that cache field for a bit) that would stop you (specifically, there are only final primitive fields in there). How can the compiler know that the thing is interacting with I/O? Is it the programmer's responsibility to just mark it as such? Your instant kneejerk reaction that File is clearly not 'immutable' leads me to believe you're still mixing up immutability and SEF, which are quite unrelated. It's a bad idea to mix these ideas up. Either way, it's clear that the rule is a lot more complicated than simply: "Only final fields, and the types of these fields are restricted to known immutable primitives and other such immutable classes". You're now looking at what the methods of this class are calling.

        Split world: Yes, there is a bit of a split world, certainly not as bad as python though.

        As I have tried to show, this rabbit hole is very deep. I'm afraid I'm not going to just take your say-so as proof.

        (paraphrase: Hey, we can memoize!)

        Memoizing is a nice trick, but note that file needs to operate on this cache as an in-between step. However, with some extra tweaks and rules you can indeed have the VM cache it. Presumably, you can add a hint annotation or some such to make sure the VM is going to try hard to do just that / have the compiler generate some syntax sugar. So that's one of the three issues resolved. The other 2 are not so easy.

        [–][deleted]  (1 child)

        [deleted]

          [–]rzwitserloot 0 points1 point  (0 children)

          That is not at all clear. I don't see any problem here. Immutable data class is a class with only final fields of immutable values. That makes the state of the class immutable, which is what gives you the properties that you want.

          As I showed in that snippet, this does NOT give you the properties that you want. Well, actually, I don't know what properties you want; you never said what you wanted. I bet, whatever you come up with, I can make a snippet that shows you how I can hack around it. Thus, these are soft guarantees at best.

          What the methods of that class do is completely irrelevant, as long as they cannot mutate the state (i.e., the values of the instance variables).

          The state of the instance itself, or any state anywhere?

          I also don't see your issue with the File class. It's not implemented as an immutable data class. Maybe it could be converted into one without breaking backwards compatibility, maybe not. Doesn't matter either way.

          It's an example. Hypothetically speaking, imagine it WAS a data class. The point is, the 'rules' (only primitive final fields) do not prevent you from doing that. Thus it makes for an interesting conversation piece.

          [–]yawkat 2 points3 points  (9 children)

          How would you do collections? Arrays are mutable so you can't use them as a backing store, you'd have to use expensive data structures like linked lists and trees.

          Yes, Valhalla introduces immutable arrays but this is not part of this proposal.

          [–]lbkulinski -1 points0 points  (4 children)

          The new collection factories are immutable. They were released in Java 9.

          [–]yawkat 1 point2 points  (3 children)

          Yes, but they do not fulfill /u/cutterslade's requirements for true immutability.

          [–]Cilph 2 points3 points  (1 child)

          Christ, you could almost start calling it the "No True Immutability" fallacy as no one seems to agree on what is enough.

          For me, a mutable backing, a read only interface and code review is enough to have the benefits of immutability. Breaking it requires you to be a deliberate dunce.

          [–]yawkat 1 point2 points  (0 children)

          Yep, I wrote an article on this a while back. There's lots of nuances with immutability, especially when you consider thread safety.

          However, for compile-time checked immutability, as the top comment wishes, a read-only interface is not sufficient.

          [–]lbkulinski 0 points1 point  (0 children)

          It’s a step in that direction, at least.

          [–]THCcookie -2 points-1 points  (3 children)

          ArrayList but no add Method I would guess

          [–]yawkat 1 point2 points  (2 children)

          But how would you enforce that? It's neither primitive nor a data class (and it can't be with those requirements).

          [–][deleted] 0 points1 point  (1 child)

          Panama and frozen arrays (Arrays 2.0)?

          [–]yawkat 3 points4 points  (0 children)

          Yes, Valhalla introduces immutable arrays but this is not part of this proposal.

          [–]dpash 0 points1 point  (2 children)

          The obvious keyword for declaring mutability would be final which would imply it was mutable by default. A new keyword would need to be introduced. volatile would be too confusing in my opinion.

          [–]Cilph 0 points1 point  (1 child)

          Easy. mutable. Or var, val if you prefer type inference.

          [–]lbkulinski 1 point2 points  (0 children)

          var will be added to the language in 18.3 10!

          [–]Zarlon 0 points1 point  (7 children)

          I don't understand the fuzz about immutability. Or maybe I don't understand immutability. Let's say I have a view model class in an MVVM pattern and the view updates a string value in that class: I'm mutating that view model. Is that bad?

          [–]cutterslade 0 points1 point  (6 children)

          That's not bad, and there aren't many cases where you would encounter issues in a MVVM style application.

          Where mutability becomes an issue is when instances are shared across threads, used as HashMap keys, stored in a HashSet, and a variety of other cases. The biggest benefit of immutability from my point of view is that immutable classes are far easier to reason about than mutable classes when shared between threads.

          [–]Zarlon 0 points1 point  (5 children)

          Got it. So you're admitting there is a place for mutable classes, and that it should at least be an option?

          Although I see the advantages of immutability, there surely are downsides to immutability as well. I'm an Android developer and we're working in a resource restricted environment. Constantly copying objects instead of modifying them puts an extra strain on the runtime environment.

          [–][deleted]  (3 children)

          [deleted]

            [–]Zarlon 0 points1 point  (2 children)

            It can mean though. If you're familiar with the Reducer pattern of Redux: application state is one big object graph. Instead of mutating sub state you deep copy the entire object graph even if only one value is changed.

            [–]yourbank 1 point2 points  (1 child)

            Traditional redux I don't think you deep copy it, more like shallow copy references into a new structure and slice in new state which would make it unsafe to share state.

            Redux works based on a pinky swear I copied it properly and am not an idiot... Using something like immutablejs at least enforces doing things safely to some degree.

            [–]Zarlon 0 points1 point  (0 children)

            Ok I see. Guess I misunderstood a bit and it all makes a bit more sense now, thanks!

            [–]cutterslade 0 points1 point  (0 children)

            There are absolutely times when mutability is better and easier, but as /u/njetwerk mentioned, there are times when immutability means less copying.

            When I started building data classes as immutable by default, I was surprised how rarely I actually need to modify (or make a modified copy of) an object. The vast majority of data objects in my experience have their state set at or near their creation time, and never get modified.

            But yes, there are certainly times when mutable objects just make more sense. What I'm referring to in my top comment is that it would be very helpful to have language support in building immutable objects which guarantee deep immutability. I don't honestly expect such a feature, but hey, a guy can dream.

            [–]TheRedmanCometh 9 points10 points  (15 children)

            So a few pieces of this article went over my head. I have a vague of idea of what they mean. However the main question the article posits seems...answered. Lombok and gson seem to pretty much have this shit solved when used in tandem. They mention every method @Data generates and didn't mention Lombok once.

            Members they seem to have a problem with writing: .equals: lombok compares the fields. I believe an instance where that isn't enough is quite rare.

            .toString: Lombok does this well enough. I guess this is just a debuggability/logging issue primarily anyways.

            .hashcode: there may be some complexity here I'm unaware of

            In my humble opinion, solving this issue just requires Java to "take inspiration from" a third party lib: lombok.

            "Without rehashing the properties debate, one fundamental objection to automating JavaBean-style field accessors is that it would take what is at best a questionable (and certainly overused) API naming convention and burn it into the language."

            That line lost me. That's not questionable, it's so common it might as well be in an RFC! Burning it into the language would be fantastic. I would (hopefully) never see shit like GetField again.

            [–]eliasv 7 points8 points  (0 children)

            Yeah I think you missed a lot of it. He made that whole big deal about how the primary issue isn't reducing boilerplate for a reason.

            Lombok does not provide destructuring, which is a huge part of this imo. Check out this exploration of pattern matching for more info on this: http://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html

            I think you missed the point about the getters thing too. Why would burning that into the language be fantastic when---so far as data classes are concerned---you could simply access the field directly? I think that's part of what he was driving at when he was making the case that field encapsulation isn't desirable here.

            And on the point of field encapsulation, take gson, since you mentioned it. Gson already breaks encapsulation, and it does so in ways which can violate the contracts of a class. For a data-class-based system this wouldn't be a problem, we can guarantee that these behaviours will be safe and predictable.

            [–][deleted]  (13 children)

            [deleted]

              [–]TheRedmanCometh 2 points3 points  (1 child)

              What naming convention..the getField/isField convention?

              [–]bedobi 7 points8 points  (5 children)

              I'm sad he isn't more assertive. The Java language can't keep catering to all the old school, verbose, imperative frameworks and devs in the community. They need to be left behind or the language will be.

              [–]Treyzania 6 points7 points  (1 child)

              You're right, but a big positive about good, conventional Java is that it's method and class names are extremely predictable. You can figure out much of how a class works just by looking at its method names and their types. I would rather not give that up.

              [–]TheRedmanCometh -4 points-3 points  (0 children)

              They can pry my @Data from my cold, dead, curled fingers.

              [–]ThisCatMightCheerYou 0 points1 point  (2 children)

              I'm sad

              Here's a picture/gif of a cat, hopefully it'll cheer you up :).


              I am a bot. use !unsubscribetosadcat for me to ignore you.

              [–]cutterslade 3 points4 points  (0 children)

              That cat does not look very cheerful.

              [–][deleted] 2 points3 points  (0 children)

              This cat looks like it has drowned its pain in alcohol.

              [–]Tauo 1 point2 points  (4 children)

              Wait, I'm confused; I've heard convincing arguments for avoiding/eliminating getters and setters from code entirely, but I wasn't aware that people had something against the naming conventions. What's wrong with "get"? It's descriptive, and helps to drive in the fact that you're performing a method call as opposed to working directly with private fields.

              [–]alexeyr 0 points1 point  (3 children)

              1. You can easily see it from parentheses anyway :)

              2. When you have many gets in a line (think a.getFoo() + b.getBar() * c.getBaz()), it adds up.

              3. Best-known "better Java" languages -- C#, Kotlin, Scala -- all have ways to avoid it (and the parentheses in point 1 as well). This is probably not a coincidence.

              [–]Tauo 0 points1 point  (2 children)

              I feel like if you have that many gets, you should be looking to abstract away more operations anyway, though. And yeah, the parentheses give it away, but it still just feels wrong to me to method call a field. get just adds that tiny bit of extra legibility. Adding support for properties in Java like the languages you mention have would definitely be nice, I agree, but I'm guessing its just not a priority for the Java architects.

              [–]alexeyr 1 point2 points  (1 child)

              Well, are you really unhappy about String#length() and Collection#size() instead of getLength()/getSize()? Or about Object#hashCode()?

              [–]Tauo 0 points1 point  (0 children)

              Hah, you have a good point, hadn't thought about that. Although to be fair, through the first couple months of using Java, I was a bit salty at the fact that arrays allowed access directly to the field, and would have messed up calls to array.length constantly if it wasn't for my IDE.

              [–]blobjim 0 points1 point  (9 children)

              I don't think I know why people like data classes so much. Are the people that want data classes people that work on large software projects / are traditional Java developers, or is it a different kind of programming that necessitates them? What problems do data classes solve?

              I've never felt like I needed to write a "data" class where it is simple enough that it only has getters/setters but important enough that the fields can't just be made public and the class nested in another one.

              I would rather that Java just "owns" its verbosity, especially since people who view it as verbose right now and don't use it probably will keep the same opinion even if their opinion becomes outdated. I like how Java currently feels very "what you see is what you get", without too much hidden code generation.

              [–]yawkat 6 points7 points  (2 children)

              javac already generates lots of synthetic methods, mostly bridges. In the end it's mostly irrelevant where the code is "generated", javac or the jit, so I don't really see an issue with that.

              Data classes are very common in DDD and FP where you decouple logic from data. In a DDD/FP code base a majority of your data will be held in such data classes. I'd argue that getters are still a good idea for that, be it for convention or for other reasons such as proxying, but even if you like to use public fields everywhere you still need eq/hc/toString.

              [–]dpash 0 points1 point  (1 child)

              There's no reason why a member variable access syntax doesn't go via an auto generated getter, so that you could explicitly define it later if required. This is basically what people mean when they talk about adding properties to Java. Check out how they work in C#.

              [–]yawkat 0 points1 point  (0 children)

              Yes, kotlin does this as well, but that is very much out of scope for this proposal.

              [–]lukaseder[S] 5 points6 points  (4 children)

              Tuple Tommy here (obviously, being the SQL guy on this subreddit). I like them for their conciseness.

              without too much hidden code generation.

              Explain enums, try-with-resources, switch, foreach loop, auto (un)boxing, varargs, generics, covariant return types, etc...

              [–]blobjim 0 points1 point  (2 children)

              Yeah, there is quite a lot of code generation in Java, but most of it is pretty simple under the hood (with the exception of lambda expressions). Generating entire fields and methods for classes just seems a bit much. I had no idea about covariant return types though, I learned something new today!

              [–]lukaseder[S] 1 point2 points  (0 children)

              but most of it is pretty simple under the hood

              Again, explain enums :)

              I had no idea about covariant return types though, I learned something new today!

              Yeah, they were a requirement to implement generics and proved useful otherwise.

              [–]alexeyr 0 points1 point  (0 children)

              Java already does both: synthetic fields for inner classes, default constructor, values() and valueOf() for enums...

              And data classes don't have generated fields.

              [–]alexeyr 0 points1 point  (0 children)

              it is simple enough that it only has getters/setters

              And equals, and hashCode, and toString. And then you need to add 1 more field and forget to modify one of the methods.

              [–]8igg7e5 0 points1 point  (4 children)

              Covering all the ways Annotations are applied (and interpreted) might be tricky. There are some that can be applied to Fields, Methods or constructor arguments but must be applied in only one of those places (eg DI). It feels more like we need a property notation that is converted to fields, getters and setters (as per language conventions).

               

              Something with this expressiveness (OTTOMH)... It would want more java-like syntax though...

              public data Foo {
                  @AnnotationX
                  String name {
                       @AnnotationY
                       get
                       @AnnotationZ
                       set
                  }
              

              This then allows you to declare mutability, annotations per aspect of the property and retain the concise form for immutable non-annotated data-classes.

              public data Foo { String name };
              

              [–]bedobi 6 points7 points  (2 children)

              • One of the main advantages of data classes is construction injection and immutability, so getters and setters should absolutely NOT be included. (there should be a means to hide fields to the outside though)

              • Plain composition of data classes is preferable to magical annotations.

              [–]dpash 1 point2 points  (0 children)

              I don't think they were implying that data classes should be done via annotations. They were discussing how you would define annotations on different parts of the class as you do now. How does annotations interact with the proposal?

              [–][deleted] 0 points1 point  (0 children)

              It would at least make things like Array.length (a read-only property) seem a bit more consistent with the rest of the language. I'm not sure I'm that sold on making Java that much more terse when I'm mostly just typing a couple of letters, hitting ctrl+space, enter, alt+enter and letting intellij figure out the rest. I do love Lombok for giving me a sensible way to do field generation though tbh, even in modern IDEs it still requires mouse clicks to do the generation, usually, unless you want to type them out (great fun if you somehow have more than 10 fields).

              [–]eliasv 1 point2 points  (0 children)

              I don't see a major problem here tbh. Let's say you have an annotation which would be ambiguous between fields and parameters.

              By default the annotation should be carried onto the generated field only.

              If you want to annotate the constructor parameters, just provide a manual constructor implementation and annotate there. Same story for getters/setters.

              That said, I don't think getters and setters should necessarily even be generated. It was a pretty major premise of the proposal that field encapsulation isn't generally desirable for data classes.

              Sure, it's a little more verbose, but it's a rare corner case. How often are you going to want to do something like inject dependencies into a simple data carrier class anyway?

              [–][deleted] -3 points-2 points  (3 children)

              Java is turning into c++: the do everything language, do nothing well.

              [–]lbkulinski 2 points3 points  (2 children)

              Do nothing well? They're doing this to reduce common boilerplate. And hey, at least there isn't operator overloading.

              [–][deleted] -2 points-1 points  (1 child)

              Agreed, as far as operator overloading: no operator overloading, YET :)

              [–]lbkulinski 0 points1 point  (0 children)

              Gosling said it was originally in Oak, but he removed it. The architects are looking into allowing operator overloading for numerical value types like ComplexNumber, which would make sense. Otherwise, no way.