Hacker News new | past | comments | ask | show | jobs | submit login
Data Classes for Java (java.net)
261 points by mfiguiere on Nov 1, 2017 | hide | past | favorite | 205 comments



... To write such a class responsibly, one has to write a lot of low-value, repetitive code: constructors, accessors ...

If you're writing a plain data class, why on earth would you write getters and setters? Just make your fields public and be done with it.

I will be forever perplexed by the idea of getters and setters (and this extends to C#s syntax sugar). I have no idea what problem they solve. If you're at the level of plain data, then just make a class with public fields and no methods. If you're trying to write a 'higher level' object - then don't refer to the names of fields in your method names. The getter/setter/property approach is just the worst of both worlds. They make explicit reference to an objects internal fields, while at the same time obfuscating what happens when you actually access them.


> obfuscating what happens when you actually access them

This is the point, AFAICT. In languages with both primitive "read/write field" operations that can't be interceded upon, but also with interfaces/protocols, "obfuscating" (encapsulating) a field access in getter/setter methods is how you allow for alternative implementations of the interface/protocol.

Specifying your object's interface in terms of getters/setters allows for objects that satisfy your interface but which might:

• read from another object (flyweight pattern)

• read from another object and return an altered value (decorator pattern)[1]

• read from an object in a remote VM over a distribution protocol (proxy pattern)

Etc.

Then a client can build these things and feed them to your library, and you won't know that they're any different than your "ordinary" data objects.

You don't see this in languages with "pure" message-passing OOP, like Ruby or Smalltalk, because there's no (exposed) primitive for field access. All field access—at the AST level—goes through an implicit getter/setter, and so all field access can be redefined. But in a language like Java, where field access has its own semantics divorced from function calls, you need getters/setters to achieve a similar effect.

And yes, this can cause problems—e.g. making expected O(1) accesses into O(N) accesses, or causing synchronous caller methods to block/yield. This is why languages like Elixir, despite having dynamic-dispatch features, have chosen to discourage dynamic dispatch: it allows someone reading the code to be sure, from the particular function being called, what its time-and-space-complexity is. You know when you call MapSet.fetch that you're getting O(1) behaviour, and when you call Enum.fetch that you're not—rather than just accessing MapSets through the Enum API and having them "magically" be O(1) instead of O(N).)

---

[1] Which is a failure of the Open-Closed Principle. That doesn't stop people.


I like Swift's approach to this. (I'm sure other languages do it too, that's just the one I know that does this.)

If you write a property (what other languages might call a "field") then by default it's a stored property, i.e. it's backed by a bit of memory in the object. If you need to take actions on changes, you can implement a willSet or didSet handler to do so. If you need to change how the value is stored and retrieved altogether, you can change it to a computed property, which invokes code to get and set rather than reading and writing to a chunk of memory. All of this is completely transparent to the caller.

It's particularly interesting because it still acts like a mutable value. You can still pass a reference to such a field into an inout parameter using &, or call mutating methods on it. Behind the scenes, the compiler does a read/modify/write dance rather than mutating the value in place.


I really, really dislike Swift's approach. get/set/willSet/didSet -- so much complication to preserve the illusion that you are operating on a field when you are actually doing no such thing. Why is this desirable? It reminds me of a class of C++ footguns where some innocuous code is actually invoking member functions due to operator overloading.

I think that Java got this one right. (I do not at all like the cargo cult custom of getter/setter methods for fields; I'm referring to the language only.)


GP was referring to the feature that getters/setters are invoked with property access. Swift's didSet/willSet distinction is unrelated to this feature. ES6 JavaScript, for instance, has this feature with just get/set methods.

In Java (and JS) there's a separate, all-knowing garbage collector, while swift is reference counted. In an ARC runtime, the didSet/willSet distinction avoids explicit calls to release the object, which is pretty clearly a good thing on the programmer's end. You can debate whether the benefits of full garbage collectors outweigh their performance characteristics, but given ARC, the didSet/willSet distinction definitely makes sense.


Today's fields are tomorrow's computed properties. Fields are rigid and cannot be changed without recompiling dependencies. Notice how few fields there are in Java's standard library. Why have fields at all?


How many times have you run into this in your career (the need to convert "today's fields to tomorrow's computer properties")?


Plenty of times! The situation where a library released to third parties requires internal structural changes is not an uncommon one. What do you do? Break every piece of third party code or satisfy the new structure and the old interface simultaneously with a computed property? "Move fast and break stuff" doesn't always have to include breaking stuff.


Honestly, many times. A common occurrence is singular evolves to multiple: "the touch position" becomes "the touch positions," "selected item" becomes "selected items", etc. The backing storage switches from T to [T].

In this scenario it's easy to make the old method do something sensible like "return the first item." But maintaining an old field is more difficult: you can't make it lazy, you can't eliminate its backing storage, etc.


Quite often, especially if you make a variation of an existing class (or an extra type in an ADT).

Scala does this quite transparent. Something defined as a `var` (variable), `val` (immutable variable), `lazy val` (lazy immutable variable) or `def` (method) is called source- and binary compatible from the caller side.

I've never seen this trick anyone, except for maybe unexpected bad performance.


Aside, from what the other poster mentioned, one major advantage is that I don't want to write getXXX and setXXX, everywhere where I do need computed properties, does it matter if the value is precomputed or lazy computed (for example for a float derived from another float)?


Enough times that I remember it. Luckily, with modern IDEs, going from fields to accessors is just a "refactoring" menu away.


YAGNI. Seriously. That pretty much describes the main problem with Java - "maybe we'll need this coffee maker to also do julienne fries in the future!"


> But in a language like Java, where field access has its own semantics divorced from function calls, you need getters/setters to achieve a similar effect.

I think the problem with Java's approach wasn't just in allowing primitive slot access, it was in making that access be simpler and use less boilerplate than accessor access, so people are tempted to use it where it isn't really what they specifically want, and accessors feel like extra work. I think that most of the time when people complain about getters and setters, their main issue is just the extra syntax they require in languages like Java.

In contrast, Lisp makes using accessors the path of least resistance, so if someone does use primitive slot access, they probably consciously really wanted that. In a class definition like:

    (defclass my-class ()
      ((x :accessor x)))
The :ACCESSSOR option lets you write (x instance) and (setf (x instance) new-value); with or without it you can write (slot-value instance 'x) and (setf (slot-value instance 'x) new-value) for primitive slot access. It's really just a shorthand for defining methods like:

    (defmethod x ((my-class my-class))
      (slot-value my-class 'x))

    (defmethod (setf x) (new-value (my-class my-class))
      (setf (slot-value my-class 'x) new-value))
But just by providing that little shortcut (and by not having a shortercut for primitive access) it's enough to make getters and setters the default in a way that people rarely complain about.


The thing about CLOS accessors is that they define methods; they are not just for the sake of having the (setf (foo obj) val) shorthand.

By saying that you have an accessor x, you're writing a method called x. Actually two: x and (setf x).

You can write auxiliary methods for these: with :around, :before and :after methods you can intercept the accessor calls to do "reactive" kinds of things.


Design patterns are bug reports against your programming language. -- Peter Norvig

Java sure has a lot of patterns.


Appeal to authority. Show me a language with little to no patterns.


I don't think there is a language without patterns. But in other programming languages (Lisp, Haskell), we just call them functions.

Edit: Actually, I think your request is even more ridiculous. If what Norvig is saying is true, then every language has patterns, because every language has bugs. So you are asking to substantiate his statement by providing a counterexample.


About your edit,

It's Pattern => Language bug, not Language bug => Pattern. You are assuming the opposite meaning.

In other words, not all bugs are patterns but all patterns are necesarily bugs (not IMO, it's just the interpretation).


I agree that you're right in strict logic sense, but the statement that everything has bugs is already tongue-in-cheek.

Anyway, what I really meant was that every language has semantic limitations that can manifest as patterns which the users have to apply. Even Lisp (static type checking) or Haskell (dependent types).


Bingo!


Then what are the design patterns for Scala?


1. Cake pattern (now considered more of an antipattern I think).

2. Extending existing class with implicit conversion.


I would be interested in that elusive language in which nothing is repeated twice.


Parentheses Hell.


I think getters/setters are an abomination resulting from a sensible OO idea taken too far.

Having private fields and public methods has benefits that are so obvious that I won't belabor the point. Sometimes -- maybe even often -- you really do want to get and set some fields, so then you have getters and setters. But applying this pattern blindly, to all fields, is insane and, as many people on this thread have noted, defeat the point of private fields and public methods. Just make the fields public, because that's how much protection you have anyway. (Adding code around the getting and setting is, of course, easier with methods already in place.)

I think this trend really got started with Java Beans, in which getters/setters were required (unless you wanted to write yet more code to nominate other methods as the getters and setters). And then the stupidity set in. Well why wouldn't you want your object to be a bean? Beans are good! Be a bean.

I believe that things like corporate coding standards then kicked in and made this nonsense unavoidable.


just use a struct for plain data


If you have a temperature class with a celsius field and change the internal representation to kelvin you have to update all client code to call a conversion method. C#s syntax sugar allows you to slot in the conversion method without a breaking change but it screws with the cost model of field accessing when used unresponsibly. Java doesn't have it so you would have to hide everything behind getters if you don't want to tie yourself to a representation.

Whether a data class should touch enough code to make the transformation a burden is another matter, though.


FWIW, I've been writing software professionally for more than 15 years, and I've literally never come across this problem. It feels contrived to me.

However, there are many different types of programming, so I'll concede it the technique could be useful in domains I'm not familiar with. But if there any such situations, then I don't think they explain the wide popularity of getters and setters.

I rarely use getters and setters and it's never been a problem. I also don't use public fields unless the class is only public fields (and the language doesn't have some kind of record/tuple type), as another commenter mentioned.


I think the popularity of getter and setters come from a mix of dozens of small problems to solve.

Protection from internal representation change is one. Expliciting what can be done with a property is another (i.e force write only or read only properties by only exposing a setter or a getter). Exposing “virtual” properties that are a combination of “real” properties (i.e. exposing a string representation of a price with a currency for instance, where both the price and currency are independant properties). Spying on getters and setters also helps for testing. And so many other potential uses.

Each use case is not a big deal on its own, but there is enough chance to hit at least one of the potential use case for at least some of the objects that autogenerating getter and setters for basically everything is seen as a good practice. Also no one gets fired for putting getter/setters, the reverse could be true.

I personally prefer contexts where I don’t have to care so much about all the above (this means less protective programming in general), but in a lot of enterprisey applications generating getter/setter everywhere is just a way of life.


How about this non-contrived example:

Certain data types (Array, Java.util.Date) expose private information if you just blindly return your instance variable to the caller. Setting can be dumb, but you may want to create a defensive copy to hand back on get.

C# syntactic sugar makes that apparent to the reader.


I appreciate you thinking of an example, but I guess I find it a bit convoluted.

Couldn't you also refactor that by changing the constructor of your temperature class so it converts things to Kelvins, rather than converting it every time you call the getter?


Sure, but every field access like

    Temperature temp = Temperature.fromCelsius(13);
    ...
    System.out.println(temp.celsius);
would have to be changed to

    System.out.println(temp.getCelsius());
when the internal representation is changed.


I get what you're saying, but at the same time I don't understand how you'd implement the class and why.

    class Temperature {   
        public final double celcius, kelvins;

        Temperature(int celcius, int kelvins) {
            this.celcius = celcius;
            this.kelvins = kelvins;
        }
        
        public static Temperature fromCelcius(int c) {
            return new Celcius(c, c - 273.15);            
        }
    }
What's wrong with that approach, and how would you do it?


Why would you have two separate temperature values?

Just have one in Kelvin that can't go below zero, and have getters and setters that translate to C/F when specified.


What you propose wouldn't be using "getters" to me. They just sound like normal methods.


This only works if your class is immutable. If a client sets either of those fields, they will now be out of sync.


Why have a mutable class to represent temperature - a simple value class with two fields? Why not just construct a new Temperature? I mean if performance was an issue, you'd just use plain doubles instead, right?

I'm open to the idea that setters do have a use case, but I'm not seeing one here.


How about a class that stores temperature and the current state of the satellite? It's easy to come up with circumstances where requirements change.


Then I would implement it as a "real" class, not a data one.

    class Satellite {
        Coordinates coordinates;
        double celcius;

        /*** constructors, etc ***/

        public double Celcius() { ... }
        public double Kelvins() { ... }    
        public void Move(...) { /* modifies state */ }
    }
Note how none of the methods make any mention of low level operations like setting/getting internal fields.

You could make the argument that I do have a getter there, Celcius. But at the risk of pedantry I'd argue it isn't so. The name doesn't imply that it's retrieving the value of a field - ie the internal representation could easily change to Kelvin or Fahrenheit - where as "getCelcius" definitely tells me there's a field there called Celcius.

Hmm, after writing that I wonder what the definition of a setter actually is. I have no problem with a method that just returns a field, as long as it doesn't go out of its way to tell me that's exactly what it's doing. Maybe the distinction I am making is too subtle.


Celcius is definitely a getter. The name absolutely implies that it's retrieving a value because it's name is not a verb or action.

Properties in C#, for example, really just remove the ambiguity in this exact situation. Is it object.Celcius or object.Celcius()? A good C# programmer would use the former. A method would be object.RaiseTemp().


It looks like I have a really different definition of "getter" than some people here. I would only call something a getter if it explicitly makes reference and effectively exposes an internal field. Just giving a method a noun name is not enough to make it a getter, in my mind. It's the "get" prefix that says 'hey there is definitely a field in here called Foo that we think we're encapsulating but we're really not'.


Your definition of getter and setter are way too narrow. You exclude all getXX() and setXX() methods that don't directly manipulate a field and all C# property get/set the same way.

The getter or setter is part of the public interface of the object. The public interface makes no guarantees about implementation -- encapsulation is one of the fundamental principles of OOP. It is only supposed to appear from outside that you are getting/setting some internal property of the object. And that is the simplest implementation. However, the value of encapsulation is that it really doesn't have to implemented that way. Or the implementation could change entirely as long that public interface works the same way.

> I would only call something a getter if it explicitly makes reference and effectively exposes an internal field.

I think you're original question is "Why would anyone use a getter/setter if they could just a public field?" But your definition excludes all the reasons why someone would do it! If getters/setters just exposed internal fields and never anything else then they really serve no purpose.


I think you're not understanding what I'm saying. Luckily this person explained it better than I could.

https://news.ycombinator.com/item?id=15607598


I think I already addressed that point adequately here:

https://news.ycombinator.com/item?id=15607812

There simply isn't a better domain method term for moving data from one place to another than get/set. You could invent alternatives but they're just more confusing.

And even that linked comment addresses modification not retrieval. Sometimes you just want a value out of an object -- a getter.

I think understand the point that you're trying to make; the idea that an object just accepts messages that alter it's internal state but otherwise keep it completely hidden is a pervasive one. Exposing internal state can lead to coupling or violate the single responsibility principle. But that model is too simple, plenty of objects are just containers. And not dumb containers that are just bundles of simple fields but smart containers with data that isn't entirely internal.


The scenario being discussed was a class which changed its internal representation without breaking it's public api.

A getter can then by definition not simply refer to only a field anymore as that field is gone. It might have done so in the first version of the class where Fahrenhet() simply returned your fahrenheit field(a getter) but now we've removed that field and replaced it with a celcius field. That means Fahrenheit() doesn't just return a plain field anymore, there is some transformation going on. It's still considered a getter.


The concept of getters & setters exist in languages where it's not conventional to write them as methods named getX() or setX(y).

Writing the that example in C#, you'd likely have

    public double Kelvins {get; set;};
    public double Celsius {
        get { ... }; 
        set { ... };
    }
and [modern] Javascript could have

    let kelvins;
    get celsius()  { ... };
    set celsius(c) { ... };
And you'd set both of them with [eg] s.celsius = 5. This is how getters/setter look when a language supports them.

Writing and using methods named 'getX' and 'setX' is conventional in Java because support for this feature doesn't exist at the language level, but is essentially implemented by the common IDEs. Probably not the ideal situation, but that's where Java is at.


what if the constructor's not the only place you can set the value?


This is a bit abstract to me. I don't tend to write mutable classes. And if I do mutate fields, it's for a "reason" (and I'll name the method after that reason).

If you feel like it, write out how you'd implement the class and why. I posted a fairly strong opinion, but I'm happy to have my mind changed.


sure, ok, if you only write immutable classes, by definition you never need setters, right?

i won't defend mutable classes (i won't decry them either), because i haven't personally thought tons about the benefits of immutability. i mean, i can see a lot of reasons why it's a good thing to shoot for, and i think it's a thing i often try to shoot for. but people often write mutable classes, or must maintain mutable classes written by their predecessors. in which case, setters can be nice.

or they can be annoying boiler plate. seems like a case by case thing to me. i think the getter/setter thing does often feel needlessly verbose, and so i upvoted your original parent comment. but "setters are always bad and i don't understand why anyone would ever use them" seems like a needlessly hard-line sentiment, IMO.


If you have a mutable class, and you're modifying its fields, you're doing it for a reason, right? Often it's part of a larger operation. So why not name the method that mutates the field after that reason. I got away from thinking about "I am altering the internal representation of this struct + vtable" to "I am sending a message to this opaque thing and I don't really care how it's done when I'm outside the black box".

> but "setters are always bad and i don't understand why anyone would ever use them" seems like a needlessly hard-line sentiment, IMO.

I have a strong opinion because I read some compelling arguments, thought about a lot, stopped using setters, and the quality of my code improved. I don't see a need to moderate my opinions on programming, especially when that's what I really think. Again, happy to be shown a great counter example and admit I was wrong.


> If you have a mutable class, and you're modifying its fields, you're doing it for a reason, right? Often it's part of a larger operation. So why not name the method that mutates the field after that reason. I got away from thinking about "I am altering the internal representation of this struct + vtable" to "I am sending a message to this opaque thing and I don't really care how it's done when I'm outside the black box".

> > but "setters are always bad and i don't understand why anyone would ever use them" seems like a needlessly hard-line sentiment, IMO.

> I have a strong opinion because I read some compelling arguments, thought about a lot, stopped using setters, and the quality of my code improved. I don't see a need to moderate my opinions on programming, especially when that's what I really think. Again, happy to be shown a great counter example and admit I was wrong.

that's all fair. i think we might actually agree more than disagree. all your arguments are compelling, and i could see myself holding a similar opinion after giving the matter more thought.


This seems to deny the fact that a lot of data exists to just be stored and displayed. Probably 85% of all software in the world has a "FirstName" field/property/column in it somewhere. What name you propose giving a method that changes that value?


I guess I'd call it "changeLastName". That's closer to the domain, we don't go to the Department of Births, Deaths and Marriage and tell the clerk we want to "set" our last name. But that is being too pedantic, even for me.

I'll concede defeat. That is a pretty good example. At the end of the day, "customer details" class is actually a big bag of fields that needs some access control and validation.


If you get married, you might "changeLastName" or maybe even "rename" yourself but if you're just moving that name from one place to another you'd "set" it.

You could probably come up with lots of different names but none of them will be more clear than "set" in this case.


If moving requires a name to be set you are at constructor time, no need for permanently available setters.


Two things with that, you're assuming immutability but even a simple database entity object wouldn't be immutable. And secondly, anything over a handful of values and setting them via a constructor isn't pretty.


if it's just used for display, use a new value.

if there's more to the domain context, i'd call it rename(~). i think from the outside, it's better to articulate what you want in domain semantics, rather than implementation semantics.


i think from the outside, it's better to articulate what you want in domain semantics, rather than implementation semantics.

You've articulated here what I've actually been trying to communicate. I have no problem if a method does nothing but get/set a variable. I just think they should be named with domain semantics.


Sure, for a simple class like this I would make it immutable too.

But the example is just a demonstration of the concept - you should be able to change the implementation without changing the exposed interface. When you first write a class, it may look like a simple bag of fields. But when that inevitably changes, getters and setters allow you to do it without breaking the clients.

Even if we keep this immutable, your implementation is different in that it uses twice as much memory. Maybe it's irrelevant, or maybe it's worth the tradeoff to use more memory and have faster access to the kelvin representation.

But maybe not. If you had getters and setters, you could seamlessly try the other implementation without changing all of the client code.


But the example is just a demonstration of the concept - you should be able to change the implementation without changing the exposed interface.

My argument is that having getters and setters exposes your implementation. If you have "getFoo" and "setFoo" it exposes that your class contains a value called Foo. My argument is that you should either give your methods better names, or get rid of the pretense of encapsulation altogether and just make them public. Get/Set is just an awkward middle ground.

Even if we keep this immutable, your implementation is different in that it uses twice as much memory.

How can my implementation be different? No one else has written one (:

But maybe not. If you had getters and setters, you could seamlessly try the other implementation without changing all of the client code.

And if you had actual methods with names that didn't break encapsulation, you could do the same and divorce all your calling code from the burden of knowing about the internal structure. Again, the middling approach is the worst of both worlds to me.


> My argument is that having getters and setters exposes your implementation. If you have "getFoo" and "setFoo" it exposes that your class contains a value called Foo. My argument is that you should either give your methods better names, or get rid of the pretense of encapsulation altogether and just make them public. Get/Set is just an awkward middle ground.

this phrasing/perspective definitely brings me around more to your point.


The pattern evolved from early Java’s lack of reflection. In order to give tools the ability to set/get data, we got the JavaBean. The culture internalized the pattern, and we’ve been mindlessly doing it ever since.


This is correct. JavaBeans were a bad solution to a problem. It was Swing (or was it AWT then?) that needed it first, so that tool builders could allow widgets to have their properties customised. So the vile JavaBean conventions took hold.

I only quibble on the "mindlessly" part. I will never add a get/set in a class if it isn't needed. But invariably, in a Java project, some library somewhere insists that I have them. So eventually I find I've reluctantly added them.

Sometimes you can get away with leaving them private, sometimes not. It's a pain in the neck and like many things in Java, it should have been sorted out years ago.


> I only quibble on the "mindlessly" part.

I'll grant that you're mindful ;-)


You overestimate my abilities! I mindfully create a horribly coupled mass of Spaghetti. But it's not anaemic spaghetti ;-)


Appreciate you posting the actual history.

One thing I've noticed more and more over the years is this tendency for folks to do things that under analysis make no sense and have no benefit.

Even worse, I have a bad feeling that 20 years ago I was one of those people...


You this a lot with C and C with Classes devs, micro-optimizing every single line of code as they write them, based on urban myths or past legends without touching a profiler a single time.


I won't disagee with the mindlessly or the JavaBean origins part, but reflection was present in Java from very early days from what I recall.

It definitely is the case that reflection in the JDK would be a very slow and ungainly way to do data access so I can see the 'bean' convention being a way around that.


I can't speak to Java, but in C#, the original goal was to reduce coupling. You can add behavior to getter and setter methods without breaking binary compatibility among packages. It absolutely is obfuscation, to the extent that encapsulation is just a special kind of obfuscation.

Possibly more importantly, public fields give you no way to create immutable types.


> Possibly more importantly, public fields give you no way to create immutable types.

public readonly int Foo;

readonly fields can only be set in the constructor, great for immutable types and with much better guarantees than protected/private/no setters.


And when you want to make Foo no longer a primary value and instead calculated from some other field? When you want to add logging to every change of Foo? Every access? When you want to switch to having Foo's value come from a database? Web service?


Then that is when you have to change the public field to a property, with no change to calling code.

Reasons for going with a property from the start is if you a) ever use reflection (which would need to change depending on whether the storage is a public field vs a property) b) If you need to implement interfaces using the property. Reasons for going with a public field is for special cases where you know a lot about how inlining affects your performance. Typically in structs.

Since there is no more boilerplate used to write "public int Id { get; }" vs "public readonly int Id", in 99% of cases I'd choose the latter.


Then I'd change it to a property and recompile. If it's value comes from the database or a web service then nothing has to change, whatever is calling the service will invoke the constructor as always.

The only exception here is for public APIs, but that's a minority of projects.


> Then I'd change it to a property and recompile

You mean, change it to a property, then fix dozens or hundreds of references, possibly in downstream dependencies some of which aren't under your control and can't be changed. Sounds fun.


This isn't true. For structs you can use 'this = ...' to overwrite yourself (including readonly fields) and reflection lets you set them too.

fwiw those are both gross but I've run into both in production code (not written by me, naturally)


The same can be said for setters and getters with a backing field, you can access them through reflection. I can't remember how it works for properties with implicit backing fields but I thought they could be set via reflection as well?


You can find the backing field and set it, yes, but the name is at least not predictable because the compiler mangles it (which discourages doing this because getting a grip on the field is harder)


> I can't speak to Java, but in C#, the original goal was to reduce coupling.

If you want to reduce coupling, why not write a real method? Get/Set couples you to your class fields. If you change your class fields, your getters and setters all suddenly become useless.

Maybe I just hate the middle ground (:


No, they don't.

I have, plenty of times in the past, changed a class's implementation details in a way that results in fields being removed, without having to create a breaking change in the associated property getters and setters. All it took was changing their implementation to work with whatever the new thing was.


In my experience writing getters and setters has been boilerplate 99% of the time.

But I still write them because situations arise where you do need to change the nature of that property, sometimes dynamically, and then it's suddenly worth it. You can, for instance, change a getter and none of the class's clients need to know or care about the change.

Though I haven't used Groovy much I like their approach to this: "Although the compiler creates the usual getter/setter logic, if you wish to do anything additional or different in those getters/setters, you’re free to still provide them, and the compiler will use your logic, instead of the default generated one."


Why don't you just use plain fields, and if you need to change it later, delete the field and go fix all compile errors? That's an easy way to find all usages.

Or are you not talking about a statically-typed language which would find the errors when you temporarily delete a field?


You don't always control the code that uses it. You'll have a lot of angry customers if you break all their builds.


well, hopefully they aren't having the library update underneath them without warning. :P


> Though I haven't used Groovy much I like their approach to this

I like this a lot about Groovy as well. Groovy also provides annotations that relieve a lot of the other points too, such as @Immutable [1], @EqualsAndHashcode [2] and @ToString. It even supports meta-annotations which let you alias several annotations together as one so you can make a complete "data class" with a single annotation.

[1] http://docs.groovy-lang.org/latest/html/gapi/groovy/transfor...

[2] http://docs.groovy-lang.org/latest/html/gapi/groovy/transfor...


You might want to look into Project Lombok. It does exactly that, and it works well.


Five years Ago I started to use it. Never touched a project without again. Today I am really interested in kotlin, which provides many of these features.


Short answer: to avoid side effects from other parts of the code rippling into the data class.

Some objects are inherently mutable and exposing a reference to them allows mutability. You might not have control of all the class definitions in your data domain in order to make them immutable. Instead, a getter and setter can create equal copies and return those.

This is assuming you are talking about getters and setters on immutable objects. If you are talking about mutable objects, then they really need getters and setters to ensure that mutations on the object they return or receive do not affect them.


They are useless until one day they become extremely useful. In other words most of the time there’s minimal advantages. However by following good form you will eventually come across and instance where you have to do something and instead of having to change code in tons and tons of places, places you may not event have access to such as a public API, you don’t realize the importance. Hopefully you never across the need to do this, it’s pretty rare, but when it happens I can’t tell you how valuable it is.

The benefits are all in code maintenance. Again most of the time it’s useless but when you need I can’t tell you how incredibly useful it can be. And once you come across such an instance you never again ask why or refuse to do it ;)


Let me give a concrete example from my past. We had a public API of POJO domain objects that could be used to render templated files, think string replace. It worked great until one day someone had a special character that caused it all to fail. How do you fix this? Ask all customers to clean their values? Good luck with that!! However from our side we just added the code to clean the output, escape the special character for the templating engine, and everything worked great.

The only other option was to have thousands of customers with live systems edit their templates and or data to fix that one bad character. It affected a lot of people due to another unrelated update. Anyways had we not been forcing the use of setters and getters a solution would have been on a whole other scale! And no we couldn’t edit the template engine, etc, because in most cases it was valid.


What use did you have from the getter? That seems like a situation where you would only change the setter (or a builder if you use that pattern).


In fact you may want to edit the getter because who says you’re the one who controls the setter. As in there may be more than one way to set the value ;)


or the constructor..


Frameworks elevated the need for getters and setters, given the need to programmatically access the internals of objects.

Their overuse is also a consequence of the popularity of a programming style of code acting on data, typically within an application that has class data merely representing database entities, acted on by separate logic and constraints in an application/service layer. Behavior based object design seems to be an endangered species.


Exactly this. If you're working on a system with any need of serialization (eg to/from JSon), or presentation on some kind of view tier, or storage in a database, then the frameworks make get/set pairs inevitable, even if you fight tooth and nail not to have them.

(Of course you could avoid the frameworks, but try telling your project managers that).

Behavior based object design, as well as being an endangered species, probably never existed very much in the first place.

I wonder if Java's popularity was partly due to people being able to appear to do OO whilst actually implementing "code acting on data" systems. You got the warm OO glow without the hard work of doing any behavior driven design.


These kind of classes are structs with busy work attached. At work I feel a little guilty when I delete them over the course of refactoring but if no processing on the incoming and outgoing data is necessary then public fields are better in every way by being easier and simpler.


To provide flexibility in the future. When your data comes from a method you can change its source without changing the caller. This can be very useful and should be leveraged whenever possible.


But by definition getters and setters lack lexibility. They expose the internal representation of an object. They stop really being "objects" - high level opaque things you send messages to - and they turn into big porous bags of fields.

To clarify, I would not consider something like this a setter:

    class Monster {
        int health;
        
        void Damage(int d) { 
            this.health -= d;
        }
    }
True, it is a method that just sets a variable. But it makes no mention of that variable. It's defined in terms of its actual purpose (inflicting damage on a monster), not its implementation (modifying an internal field called 'health').

There is definitely a time and place for plain data objects. But if you find yourself actually needing validation and preprocessing in your get/set, then you probably have a 'real' object hiding their. Stop being lazy and give it proper methods.


This is a good argument and I have considerable sympathy with it, but it's actually not an argument against using getters and setters; it's just an argument for making them nonpublic. In a tiny example like this it obviously doesn't matter, but in a large, complex class it can be useful, in my experience, for all assignments to a field to go through a setter. As others here have argued, this provides a convenient hook for changing the behavior of all such assignments -- a hook which is maybe not often needed, but very useful when it is needed.

That said, I don't agree with your argument in all cases. Some classes really are relatively passive carriers of data. My favorite example is AST node classes in a compiler; the logic that controls the transformations applied to these is naturally outside the classes, because most of the interesting postconditions and invariants apply to the entire AST of which each node is only a small part.


`Technically` The current representation of `objects` in java is a abomination to the original idea behind object's. Hell even the use of class, members and fields fly in the face of what real objects are.


> "abomination to the original idea behind object's"

Whose original idea behind objects? Alan Kay and Dan Ingalls? As recently as September 2017 Gosling publicly stated [1] that Java's object model is entirely based on Simula. Object-orientation didn't start with Smalltalk, and its biggest contribution of the concept of (non-command) messaging between objects (all the way down), has proven none too popular in modern languages (excluding Objective-C), unlike those of Simula which introduced objects, classes, sub-classing and virtual functions.

Java is entirely consistent with these "original ideas".

---

[1] http://bit.ly/2xc1XTA


Do physicists argue about the true nature of gravity because Newton had the "original idea" behind it?


What do you mean by "real objects"? Are you refering to prototype OO?


Yes similar to a prototype language. The original design goals of OOP was you removed your constraints from the machine language and the restrictions that comes with a state based machine. Instead of focusing on mutex’s, member fields, private/public functions inheritance. You took your problem domain and deconstructed it using basic-level categorization into objects.

Those objects themselves would have behaviors and their own internal state. Those objects would communicate with each other via sending messages. It was up to the receiving object how it would or wouldn't reply to such a message. In this model there isn’t a type system as each object send messages to each other. To solve a distinct problem objects would delegate onto each other who would be the best to accomplish the task.

If you needed a object to have new behaviors you would just simply send a message to the object with the new routine/method/function. Just like the real world you could add/remove things from objects without any concern. In this way your objects morphed over time that where a representation of the complexity of the real world.

The problem that happened was a lot of OOP didn’t take place in the domain of the real world instead engineers moulded it to fit into a state based machine. Out went the notion of Objects sending messages to each other because it was too much of a performance hit. Out went the notion of clone objects instead replaced with a central management system such as classes. Next was the constrain of a type system, and inheritance.

The best example of a true OOP language today is javascript/small-talk/prototype languages.


"{}.f is not a function"

oh..


Getters/Setters do have a couple of reasons to exist:

1) Allowing you to validate data/morph data on your objects on set. (example: Date is not a workday)

2) Allow others to do either 1 or other actions on set/get (examples: Hibernate entity beans that update db/set dirty on set, GUI can extend object to update on set)

That said it was a total PITA when this first became popular. I spent way too much time changing code over because that was now "best practice". And don't get me started on Boolean not being get but is or has.


> If you're writing a plain data class, why on earth would you write getters and setters? Just make your fields public and be done with it.

I think it's because you can't specify fields interfaces. If you different data classes, but you want them all to be "Named", you need "getName()" on your "Named" interface, because you can say that it should have a "name" field.

Of course, that's a language flaw, but it's one that people have to work around.


Setters, at least, I find to be frequently useful places to put breakpoints when debugging. This is quite a bit rarer with getters, but I guess it happens occasionally.


If you ever have to change a fields meaning or add a new field and provide the old fields value for older clients, you can't just make it private and add a public setters and getters without breaking compatibility for all your users - not just binary compatibility but also source-level compatibility.


> If you're writing a plain data class, why on earth would you write getters and setters? Just make your fields public and be done with it

I'm not going to completely dismiss the such a practice may be plain old cargo-culting...

But as devils-advocate, properties are implemented as methods/functions, and as such (under the hood) accessed through a vtable.

This means they can be overridden in derived (generated) classes, which can then implement things like change-detection and other stuff which may be of use for a data-access/persistence class. And these derived classes can be returned in place, without the calling code knowing nothing about it.

> They make explicit reference to an objects internal fields

Not really. A property is supposed to be a public API, and definitely not "internal".


Even for just plain data values, getters and setters can be decorated with annotations that modify the member-"property's" behavior depending on context, e.g., what should happen to this member when I serialize to JSON ... or when I read from a DB?

I've found these decorators real useful in the past ... and while they balloon the code for the "data class" itself, they eliminate a lot of code elsewhere.

E.g., this may violate some "separation of concerns", but often one will want to: (a) read some hierarchical data from JSON in a web service request; (b) persist these elements to DB, maintaining proper relations between entities read in from JSON but now persisted as rows to multiple tables in a DB; (c) at some later point read back some of those elements and reconstruct the hierarchy and perhaps transform it or merge it with other hierarchies; (d) perhaps re-persist it, or send it out as a JSON response ... so ...

... in such a situation I am dealing with the same small set of "data classes" everywhere -- but when persisting or reading from a DB I have data fields that represent "primary" or "foreign key" DB values -- I possibly don't want those field values to ever get written to JSON; other member fields deal with the semantic hierarchy of that data in the JSON-like or internal-Java view (e.g., lists, maps, pointers-to-parents-in-hierarchies) ... but I don't want those members ever to be written to the DB (since they're replaced by PK/FK references) ... >>> rather than maintaining two sets of data classes for the two alternative representations (and the ugly boilerplate required to translate between them), it's much easier to have just one set of semantic data classes that each knows how to live in each context (DB, JSON, in-memory, etc. ...). <<<

The key to telling these data classes and their members to behave differently, in Java, for each context (JSON deserialize vs JSON serialize vs DB read vs DB write), is to use decorators on their setters and getters.

EDIT: included more lengthy rationale.


You'll get you run out of town with that level of heresy in most java/c# shops. Getters and Setters are great when you want finer control over what can access certain fields, in a List class for instance, I wouldn't want the length to be externally writable. But somewhere along the way it went from a useful feature in some circumstances to a mandatory feature in all circumstances.

In the c# world "public int Id;" will fail code review but "public int Id { get; set; }" will be just fine. I've never seen a justification for it though, if we make a change in future it's going to take just as much work and 99.99% of the time will never be required.

But we have to appease the encapsulation gods.


"public int Id" should fail the code review, but "public readonly int Id" should not...

public readonly int Id is perfectly fine until the property would actually be needed. The nice thing about properties is that when changing a public field "public readonly int Id" to a property "public int Id { ... }" you don't require any change of calling code. This is really the main benefit of properties over get/set methods.

Now: getters and setters are very useful once you need them. And you don't need them until you do. But there are many good reasons for them: invariants/validation and interfaces are probably the most common.


> if we make a change in future it's going to take just as much work

In Java, changing from a field to using accessor methods requires source changes on the consumer side as well as the class itself. With C# properties this is transparent in source, but I think it still requires recompilation on both sides. Not using fields, therefore, means changes have less impact on other compilation units that might consume the class.


I don't understand your complaint. The problem with getters and setters was the substantial tedious boilerplate required. C# completely does away with that to where there is no meaningful difference between the two in terms of typing required, while at the same time providing the benefit of encapsulation. So what's the problem? Do you really object to 14 more chars to type? That's absurd.


> The problem with getters and setters was the substantial tedious boilerplate required

The problem isn't the tedious boilerplate, it's that it isn't necessary most of the time, 99%+ of getters and setters could be replaced with public fields. c# solved a problem that only existed in the first place because of cargo cult practices.

> while at the same time providing the benefit of encapsulation

It potentially provides encapsulation and I don't really object to them there, but if we just used them where they were really needed then we having a setter/getter function is would have been just fine as well and the language would be simpler.

> Do you really object to 14 more chars to type? That's absurd.

I see you didn't use c# before version 3. Originally they required almost as much boiler plate as java, I've still got a mountain of code around here from that time and all they add to the codebase is noise.


> 99%+ of getters and setters could be replaced with public fields.

Actually it makes more sense the other way around. Fields are just an optimization; the different between fields and properties is one has direct memory access and the other is a method. Properties/methods are far more powerful: their implementation can change, they can be virtual and overridden, etc.

Maybe we could have had just properties and the JIT could have optimized them into direct memory access if they were backed by a simple field.


>The problem isn't the tedious boilerplate, it's that it isn't necessary most of the time

I just don't understand this POV. The cost is essentially zero so I don't see what there is to object to. That it isn't "necessary" is just a strange thing to optimize for. Unnecessary code that adds to the cognitive burden should be eliminated. But this isn't an example of that.


In Java, they came with the bean standard. The goal was to codify properties to make reflection easier. That’s it.

If you don’t need reflection or the bean utilities that help with that, just use simple public final T values.


> If you're writing a plain data class, why on earth would you write getters and setters? Just make your fields public and be done with it.

When doing pure OOP, objects should only communicate via methods, period, it's called state encapsulation and is one of the core principle of OOP, the second being polymorphism.

> I will be forever perplexed by the idea of getters and setters (and this extends to C#s syntax sugar). I have no idea what problem they solve.

Then you don't understand encapsulation.


For arguments sake you could say foo.bar = "baz" syntactic suggar for setBar("baz") sure you now cant add logic to the set method without introducing a real setBar method (and therefore breaking your public interface) but for immutable final DTO / POD style classes that don't have setters just use a public final field and be done with it

There's a difference between understanding encapsulation and being pragmatic


In C# 6, using properties is actually slightly less verbose, "public int Foo { get; }" vs "public readonly int Foo;". Also, you can easily slap an interface around your data class if you need to later. So my thinking has switched when writing new C# -- why not use a property?


You don't get to execute validation code on a bare field right away.


Why not give your "setters" a real name that describes what they're doing?

https://news.ycombinator.com/item?id=15606777

In the structs & records world (C, F#, Rust, etc) they never seem to have this issue. Either the struct is completely transparent and you can read and write fields at will, or it's completely opaque and the functions that operate on it have better names/semantics than "setField".


You're cutting out/ignoring a big chunk of the quote and then arguing a point the author didn't make. Simply accessing properties directly doesn't solve the problem.


Yes, I am. It was a separate tangent, and a bit off-topic.


If you have the option of a property later, there's no reason to start with accessor methods, but some languages don't support properties.


While I mostly agree, getters without setters is a nice way to expose that youre data is immutable rather than relying on final fields


Just use public final. That is the defacto way to make immutable data classes. Why would a data class need non final fields?


i'm a little rusty on my java, but i don't think this will work for non-constants (i.e. it won't work for things you don't set at compile time).

to my knowledge, there's no "make this a constant after the first time the value is set" declaration in java (or any language that i'm aware of).


If you declare a field final in Java, you either need to set it at declaration or in the constructor, so it will work with things set at compile time.


I do it in PHP to make something immutable. data goes into the constructor and then only getters are provided.


Some reasons:

- more efficient representation

- thread safety

- security (defensive copy)

- validation

- logging

- debugging

- backward compatibility


Getters and setters are confusing because there are no reasons to use them for small projects, like what you would build in a college course. Software becomes exponentially confusing the larger it becomes. In addition, one piece of software may be built by multiple teams, such as using third party libraries. The best way to handle the additional complexity is to split each section into two: the interface (public) and the implementation (private). Here are the reasons why:

First, change. Changes to code happen all of the time. If someone wants to build a library so that many other users can interact with it, they have to realize that one day changes to that library will need to happen. If code is separated into public and private properly, then any private functions and fields can be rewired, and as long as the rewiring makes the public functions and fields perform the same, then the change will not break anything. How important is not breaking things? Well anyone familiar with Python's 2 and 3 schism knows the pain of changes that break compatibility.

Second, visibility. When you are interacting with a large codebase, you need to know what functions and fields to interact with. IDEs have very useful tools that can list these for you, but if everything is public then they will list everything. If 90% of your codebase is private data, that is a lot of useless functions and fields to sort through!

Third, hackery. When you are building a large codebase, there may be some things you don't want you programmers interacting with it to do. Users might take advantage of quirks in your code that were never meant to be used that way. XKCD's Spacebar Heating comic illustrates this nicely. Another reason may be security, as you might not want someone to have full access to functions and fields to poke around and understand your code better.

So these are the reasons why public and private are important concepts. The problem is then if something starts out as public, it won't have any of these advantages. If you want to change it to private later on, then you are screwed. So the Java solution is to make everything private from the beginning. Vanilla getters and setters are really just making private data appear public. Then if the data needs to be changed from "public" to private, the getters and setters can be modified accordingly.

Python's property approach is a similar concept, but infinitely better, as instead of relying on a programmer to build getters and setters, the language itself invisibly builds them under the hood. Then if you want to change something from public to private, instead of being screwed, you just add a property tag with the getter and setter code to change the getter and setter from an invisible default to a visible modification.


Generating getters and setters are day jobs for 'JavaBean Jerries' which comprise most if not all enterprise Java developers.


AutoValue with Builders is nice:

  Animal dog = Animal.builder()
    .setName("dog")
    .setNumberOfLegs(4)
    .build();
https://github.com/google/auto/blob/master/value/userguide/b...


Not that nice compared to kotlin:

    data class Animal(dog: String, numberOfLegs: Int)  

    val dog = Animal(
        name = "dog",
        numberOfLegs = 4
    )
The amount of boilerplate for AutoValue builders is so ridiculous that most people use IDE plugins to generate it.


In clojure I'd write this, if I actually needed a class for type dispatch or interface implementation for some reason.

    (s/defrecord Animal
      [name           :- String
       number-of-legs :- Integer])
    
    (def dog (map->Animal 
               {:name "dog"
                :number-of-legs 4}))
The nice thing is that I could also skip the defrecord if I just want enforcement of the shape of the data by making a similar defschema and then I'd just use plain maps.


I mucked around with records a lot early on while learning Clojure, and I'm not really sure when I stopped and just started using maps. Now it's second nature and I'd only consider using a record if there was some overriding performance concern.


  data class Animal(dog: String, numberOfLegs: Int)  
and

    Animal dog = Animal.builder()
    .setName("dog")
    .setNumberOfLegs(4)
    .build();
are very different. In this case the builder pattern is more powerful as it lets you pass around builders that haven't been "built" yet. Kind of like currying.


True, but the constructor method is checked/validated at compile time vs. run time with the builder pattern. Not quite the same as your example, but Kotlin does have good syntax for copying data classes while only changing a single field - this could be used similar to your currying usage.

https://kotlinlang.org/docs/reference/data-classes.html#copy...


Here's that kotlin copy syntax

      val cat = dog.copy(name = "cat")


Nope, we just add @AutoBuilder

https://github.com/h908714124/auto-builder


A code generator for your code generator.


Agreed. The amount of boilerplate is reduced significantly in Kotlin. it has builder methods also which help greatly with data classes like apply(), with() and let() for us it became language of choice for backend for these reasons


Very similar in C#:

var dog = new Animal(){ name="dog", numberOfLegs=4 };

I use it all the time.


The big difference there would be, in the C# example you've still got to write a bunch more boilerplate for Equals(), GetHashCode() and ToString(). Kotlin's data classes give you those three for free.


now in... clojure? We usually don't use dynamic dispatch, but if you wanted to explicitly have an animal-ey map with a name and number of legs, it's:

    (def dog #:animal{:name "dog" :number-of-legs 4})


I, for one, am enjoying the ever so slow scalaization of java.


If the JVM magically got rid of nulls and Scala cleaned up some of the slightly wartier bits (implicits come to mind, although they are useful and no clue how I'd fix em...) then Scala would be my favorite language around by quite a bit.

Besides maybe Rust. Really different usecases though.


Kotlin is a great middle ground IMO. It has a lot of the expressive power of Scala but is a much simpler language.


Dotty, Scala Native, and Scala.js are all interesting projects that may just end up improving Scala in the long run. I actually love Scala as it is, so I can't imagine how great it will become when the compile times improve and the warts are cleaned up.


I've gotten to work two jobs with large Scala projects, plus one of my big OSS projects is in Scala and I really would hate to go back to a Java job.

Scala does have a lot of issues, I agree (implicits. Bleh! I know it makes DSLs easier, but I could be totally fine without DSLs. Python's Zen has it right: explicit is better than implicit), and some libraries can get into crazy insane syntax for those unfamiliar/just starting out with functional languages.

Overall I agree though. I hope the future of the JVM branches away from Java itself and more into the other JVM languages like Scala and Kotlin.


I don't think many of Scala's wartier bits will go away without Java getting its act together re: things like type erasure and a bifurcated type system, because a lot of the odder things in Scala are basically workarounds for deficiencies in the underlying platform. And I just don't see much political momentum behind either of those.


Why would type erasure affect the front end language? I'm generally interested.


One of the earliest use cases for implicits is that in Java most types are erased but Arrays aren't, so you can't instantiate an Array in a generic method without having some way to pass the concrete type through.


I do not see why this problem cannot be solved by a compiler rather than a language feature. The type is statically known. It may require additional metadata alongside class files for separate compilation, but I don't see this as a big issue.


Scala needs to interoperate with other Java languages, and there is no platform-wide spec for supplying such metadata.

Even if there were, it couldn't be statically known at compile time in the case where a library written in Scala is being called by code that was written at a later date.

And even without that consideration, types still cannot be statically known in cases where you're being handed objects whose type is not determined until run time. Which happens all the @$#% time in Scala, due to its use of algebraic data types.

So, e.g., Java's run-time has no real way of expressing the type `Option<List<String>>`. You can declare it and get some compile-time checking, but that's all erased before the final bytecode is generated. There's no such thing as `Option<List<String>>.class`. This really limits what you can do with generic code. Scala added its own parallel type tag system to get around that. It's weird as heck and only really usable from other Scala code, though.


> Scala needs to interoperate with other Java languages

But does it? Can I even use e.g. a Scala collection from Java? (let alone Clojure, Kotlin, etc) Certainly it looks easy to import and use Java objects, but that looks to be the extent of it.

> it couldn't be statically known at compile time in the case where a library written in Scala is being called by code that was written at a later date

When you build some new code that uses an existing library, any parametric polymorphic type variables get instantiated at the use sites. Where I admit this isn't true, is the adhoc polymorphic dynamic dispatch via subtyping, but this wasn't given to me as an example. I don't see that ArrayLists and ADTs should present a problem.

> types still cannot be statically known in cases where you're being handed objects whose type is not determined until run time

Again, I think you are referring to dynamic dispatch here? I agree this could be a problem in open class hierarchies. But the ADT encoding in Scala is a closed statically-known hierarchy, so I can't see why it has to cause problems. Truly "generic" or parametric polymorphic code should not depend on type tags or even be allowed to introspect the runtime type, doing so violates parametricity, which ultimately reduces our ability to reason about the code.


> Can I even use e.g. a Scala collection from Java? (let alone Clojure, Kotlin, etc)

Yup to all. Sometimes the code comes out looking a bit ugly (e.g, you can access default parameters from Java, but it's done by calling methods with kind of awful auto-generated names), but the only things you really can't get at are things that relies on implicits, type tags, or traits with fields.


The type within a generic method can't be statically known. Consider a generic library method that creates an array somewhere deep in its internals, and is called from an application compiled separately.

Now of course you can say that library method requires some extra information from its caller - but how do you reflect that in the method signature in such a way that the binary compatibility constraints are clear and it remains intelligible what the signature is when invoking that method from Java?


If it creates a specialised concrete array at runtime, then it can't be a truly "generic" method (whereby I assume generic here means parametric polymorphism?). If you want to specialise object arrays to primitive arrays for efficiency, then I do not see why this cannot be a compiler optimization, since the types are statically known at the use sites.

Perhaps Java interoperability is the reason for the choices Scala made, but it doesn't appear that e.g. Scala collections can be used from Java?


> If it creates a specialised concrete array at runtime, then it can't be a truly "generic" method (whereby I assume generic here means parametric polymorphism?).

I'd argue it is, because the semantics of an array are the same whatever that array contains. In any case, there's no nice alternatives: a lot of Java APIs use Arrays, so not being able to work with them would be unpleasant, while having contexts in which you could work with existing arrays but not instantiate new ones would be weird and not a good fit for an immutability-oriented language like Scala (it would match what Java does, but Java is a lot more mutation-oriented).

> not see why this cannot be a compiler optimization, since the types are statically known at the use sites.

The use site for the generics could be arbitrarily many compilation units away from the code that instantiates the array. If it were just primitives then we could use @specialized and generate multiple copies, sure, the issue is that Java arrays are unboxed for any type including custom ones.

> Perhaps Java interoperability is the reason for the choices Scala made, but it doesn't appear that e.g. Scala collections can be used from Java?

They can be used, though in practice it's cumbersome enough that you probably wouldn't want to. The current collections API was created after Scala was relatively well-established and so had different priorities from early language design.


Slow and steady, we don't want to have a Python 3.

When minimal value types get implemented, there will be a way to slowly fix those issues.

Likewise with the ongoing work with Dotty.


So if it became Kotlin?


To be fair I haven't really used Kotlin yet, but from my brief understanding the type system isn't quite as powerful, which is something I really like about Scala.


But it also can be annoying as a Scala programmer because you are going to have to be aware of both the Java and the Scala versions of each thing and how they differ.

For example, under this proposal, you will need "new" when creating an instance of a Java data class, but you are probably in the habit of omitting it when creating an instance of a case class.


this is why God invented the red squiggly underline in IDEs


Or just install Lombok.


Can't do java without it.


Lombok @Value for the win!


@Data seems more like what they are proposing. It comes with toString, equals, etc and has a bunch of cool features [0].

[0] - https://projectlombok.org/features/Data


As the article starts out with, Algebraic Anny, Boilerplate Billy etc wanting different things, I wonder if rather than side stepping this issue with a compromise if they could solve it with metaclasses as proposed for C++ https://herbsutter.com/2017/07/26/metaclasses-thoughts-on-ge...

I really like the idea of metaclasses and would love to see proposals for C# and Java too. As the proposal mentions Java and C# have already gone down a separate path with interfaces (and structs for C#) but would be cool to see if it could be resolved anyway.


Honestly immutable data classes that are created via builders is a must have in Java.


Make fields public final and your constructor is your "builder".


Those two patterns aren't the same. You can pass around a half constructed builder but you can't pass around a half constructed public final object like you described.


You can in most modern or functional languages, by currying/partial evaluation/binding. It's rare for data classes.

In scala:

    case class Foo(a: Int, b: String)
    val halfBuilt: String => Foo = Foo(1, _)
    val foo = halfBuilt("foo")


Is there something that a builder gets you that Kotlin-style data classes doesn't?


Builders can set multiple fields of the data class at once, e.g. from a single builder parameter. They also can perform error checking whether the thing that the user actually wanted to build is consistent before returning a data class. There might be multiple fields in a class where the value of one field restricts possible values of another one.

These are already some reasons why you want users to create objects through builders instead of initializing them directly.

Another thing that builders provide is interface isolation: If your data class is only interpreted by your own libraries code you can modify it's (package-private) content as you like and require. The builder can evolve (and fill in additional fields as needed), and your code which consumes the built data class can evolve without breaking a user contract. Just the builder API needs to be stable (or backward compatible). With data classes this wouldn't work that easy, since you require the user to specify more parameters directly.


One thing I love about builders, besides the sibling replies, is that builders force users to explicitly name the arguments. Passing args to a constructor/method/whatever with implicit argument ordering can be error-prone in certain situations (multiple adjacent args with the same type).

    c = Class(firstName, lastname)   // are these passed in the right order?
    c = Class(lastName=firstName, firstName=lastName) // obviously incorrect
Especially when you're using other magic like auto-generating constructors based on fields (as with Lombok)...then rearranging two String fields can subtly break things with no compiler errors!


Named parameters for functions (including constructors) are a good idea - better to build them in as a general case rather than making people read a lot more code to have them in one specific case. Look at what Scala does.


Interesting to see everyone discussing Java vs C# properties, when C# properties are actually based on how Eiffel and Delphi do them. :)


Why underscores in "__data"? Is this just a temporary thing?


It's decoy to avoid bikeshedding. The value class proposal used __value


When you say decoy, do you mean it's intentionally gross to keep people from going off on syntax debates?


I hope so!


Probably to avoid making 'data' a reserved word and breaking a ton of code that used 'data' as a variable name. Prior to Java 5, 'enum' was a very popular variable name too.


I'm having a difficult time trying to think of a case where "data" is the best variable name for anything.


Plus, it's 2017! There are so many tools to do a semantic search and replace and replace all variables, parameters, etc. called "data" with, let's say, "__data__". Why uglify the language instead of providing a migration tool like Python's 2to3?!


Java reserved words are reserved in all contexts. You can't have a variable called "class" because class is a reserved word. If 'data' becomes a reserved word, imagine the code that would no longer compile...


Not exactly true, but true for this use case. The new module keyword in Java 9 is only a keyword in module-info.java. You can still have a variable named module in regular class files. They wouldn't be able to pull this syntax trick with data as a keyword though.


Why not? `data class X` is currently invalid code. What is the problem with allow the `data` keyword in a class definition and not forbidding it in other contexts?


That's just not the rest of the Java grammar is designed. It would be an unwelcome edge case.


My first thought is that maybe there is an issue with inner class definitions here. Not sure how you'd define an inner data class but I'm guessing it would be similar to regular classes. If I have a `public class data` already in my codebase and then I have places where I declare a `data variable1` I think that there is potential for issues.

I don't have much experience with grammars but I feel like the more contextual the parsing rule the more likely there will be nasty edge cases.


I have experience with grammars, but not with the Java one.

There isn't an inherent restriction on context-free grammars why this couldn't happen. In pseudocode this could work fine:

    classDef = accessModifier? classModifier* `class` identifier `{`
        (fieldDef|methodDef|classDef)*
    `}`

    fieldDef = accessModifier? fieldModifier* type identifier `=` expression
    
    classModifier = `data`
    fieldModifier = `synchronized` | `final` | `volatile`
As you can see there isn't an inherent reason why the identifier rule should exclude the `data` keyword for this to work


I agree, I hope that doesn’t end up being final.

Otherwise I really like this proposal. I absolutely love the ability to do D structuring, and I like the idea that they’re going to make it possible to make these immutable as well.


So essentially Lombok?


> Can a data class extend an ordinary class? Can a data class extend another data class? Can a non-data class extend a data class?

No, no, and no. There are interfaces with default impls these days, don't allow base class state.

And figure out how to make interfaces "sealed".


Can’t we just use AOP to generate the boilerplate code if we are ok with Kotlin style data types? Toss an annotation on the class like @Data. After that everything should get generated at compile time.


Classic Brian Goetz bashing Java serialization.


"data class" is already in Kotlin flavor.

Yes, I refuse to call Kotlin a different programming language like Scala, because it's just syntactic sugar over good-ol-Java, while all tools, approaches, stackoverflow are the same. But it has the data classes, implemented just like the article described.


Have you actually used kotlin before? It most certainly has features that are much more than just syntactic sugar.


Yes, I use it every day and absolutely love it. Especially the part that it's still syntactic sugar over Java.


It does a lot more than just syntactic sugar. It expands the type system with nullable types, smart casts and covariant/contravariant generics, and it has actual closures. I agree that most of the features kotlin provides are syntactic sugar over Java, but kotlin is as much a separate language to Java as Scala is.


This seems unnecessary if the functional / lambda approach is fully adopted as the data can be understood by looking at the functions that operate on the data, so there would be less of a need for simplifying access to the data values when passing them into functions. As I have developed more data-intensive computational methods in Java I no longer implement data encapsulating classes but rather just use collections containing the basic data types.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: