3 ms·
I think the point a lot of posters are getting at is, maybe reducing boilerplate for JavaBeans is a more useful goal, given the huge ecosystem of tools and code
by thu2111 7y ago
I think the point a lot of posters are getting at is, maybe reducing boilerplate for JavaBeans is a more useful goal, given the huge ecosystem of tools and code that assumes the JavaBean pattern.
That's what Kotlin did and it's been very successful, so there's no fundamental reason why not. It's a philosophical objection of the form "mutability is bad", which feels somehow Haskellish and un-Java-like. What happened to being a blue collar language?
- pron 7y ago> so there's no fundamental reason why not That another language has done it does not mean there is no fundamental reason not to do it. A fundamental reason can be that its cost/benefit ratio isn't good enough. Other languages weigh language complexity less harshly than Java. > That's what Kotlin did and it's been very successful In what sense has it been "very successful"? That the small minority of people on the Java platform that have chosen to use Kotlin like this feature? Currently, there are still more people using Scala, does that mean that all Scala features have been even more successful? In any event, that would be a different feature, and it will be judged, and then perhaps adopted, separately. > It's a philosophical objection of the form "mutability is bad", which feels somehow Haskellish and un-Java-like. What happened to being a blue collar language? That's not the objection, and Java is still blue-collar. Records don't do that not because of some "anti mutation" sentiment but because records are about something else than reducing JavaBean boilerplate. See the discussion on mutability here, https://cr.openjdk.java.net/~briangoetz/amber/datum.html https://cr.openjdk.java.net/~briangoetz/amber/datum.html, which I'll reproduce below for your convenience: > The stricture against mutability is more complex, because in theory one can imagine examples which do not fall afoul of the goals. However, mutability puts pressure on the alignment between the state and the API. For example, it is generally incorrect to base the semantics of equals() and hashCode() on mutable state; doing so creates risks that such elements could silently disappear from a HashSet or HashMap. So adding mutability to records also likely means we may want a different equality protocol from our state description; we may also want a different construction protocol (many domain objects are created with no-arg constructors and have their state modified with setters, or with a constructor that takes only the "primary key" fields.) Now, we've lost sight of the key distinguishing feature: that we can derive the key API elements from a single state description. (And, once we introduce mutability, we need to think about thread-safety, which is going to be difficult to reconcile with the goals of records.) > As much as it would be nice to automate away the boilerplate of mutable JavaBeans, one need only look at the many such attempts to do so (Lombok, Immutables, Joda Beans, etc), and look at how many "knobs" they have acquired over the years, to realize that an approach that is focused exclusively on boilerplate reduction for arbitrary code is guaranteed to merely create a new kind of boilerplate. These classes simply have too many degrees of freedom to be captured by a single simple description. > Nominal tuples with clearly defined semantics is something that can make our programs both more concise and more reliable for a lot of use cases -- but there are still use cases beyond the limits of what they can do for us. (That doesn't mean that there aren't things we can do for these classes too -- it just means that this feature will not be the delivery vehicle for them.) So, to be clear: records are not intended to replace JavaBeans, or other mutable aggregates -- and that's OK.
- thu2111 7y agoI guess I mean successful in two senses: 1. Numerical success. Kotlin has got a lot of adoption very quickly, by the standards of JVM languages. It's now the default language for Android development having displaced Java itself as such (of course, Android continues to use the rest of the Java platform's design and continues to support Java the language). 2. The data class feature itself doesn't seem to suffer the problem of many knobs and boilerplate cited in Brian's doc. Nor does it have any major incompatibilities or surprising semantics. Actually there are no options that I can think of. You just mark a class as data and it obtains some new restrictions and features. Those aren't always appropriate but you can't really customise anything beyond overriding/replacing some of the generated methods. And by "fundamental" I mean in the computer science sense, not the tradeoffs sense. For instance if a new feature would require major backwards incompatible changes to the type system which would make it a different language. The design doc says that creating lots of new boilerplate is guaranteed if you add mutability, which is a strong claim. It doesn't seem that way when I use Kotlin data classes. It feels like a big win in boilerplate reduction even though the output is basically an enhanced bean. Yes, you have to be aware of things like not mutating objects used as map keys, same as in Java. OK. No big deal. There are fewer reasons to use mutable objects when you have copy constructors anyway so it's rare to want to do that and an IDE static analysis could warn/error you if you use a mutable type as a map key. (albeit I just checked and IntelliJ doesn't). If you look at the personas defined at the top of the design doc, which seem pretty accurate, it's notable that most of them are people who just want less ceremony (Boilerplate Billy, POJO Patty etc). I don't think the lack of mutable records will be a big deal, no more than deviating from the getFoo naming pattern will be, but these small things add up.
- pron 7y agoFirst, let's separate Kotlin's adoption on Android and on the Java platform. Android has never been Java, it is now very different from Java, and while adoption of Kotlin for Android is high (~60% according to Google), adoption of Kotlin for Java is quite low (less than 3% according to Indeed.com). Second, records and Kotlin's data classes are not the same feature and they don't have the same goals. Records are primarily about adding named product types, or named tuples, not about reducing boilerplate for mutable objects, while Kotlin's data classes allow you to add properties that are excluded from equals, which is, IMO surprising, and in any event means that data classes do not serve records' goals. That's also why there is no deviation from a naming pattern, because this concept didn't exist in Java before. Records are not beans, and there is no need for them to follow a naming pattern of something they're not; even if there is some benefit in doing so nonetheless, there is also a disadvantage. It's perfectly OK to disagree with Java's designers and think that Java should have added Kotlin-style data classes instead of records and while neither satisfies the others' goals, you think that the former's goals are more important, but that is just a matter of taste. Like Boilerplate Billy, you can think that reducing boilerplate in itself is a big benefit. But I don't think you can point at any evidence that shows the decision to implement records is wrong. So yes, Java could have added a different feature, but it chose not to.