← Back to context

Comment by rzwitserloot

1 day ago

> But ... LocalDate predated records by 6 years?

Yes, exactly - now you're getting it. Or rather I get the feeling I failed to explain it well.

ArrayList predates generics.

However, ArrayList does have generics.

That's because generics were added to the language in a 'culturally backwards compatible' way: Existing libraries (i.e. libraries that predate the introduction of generics, such as ArrayList) could modify themselves to add support for generics in a way that is backwards compatible for the library: Code written before they added it continues to work and compile fine even against the new release that added generics.

The same principle applied to records would mean that LocalDate could have been updated to turn into a record in a way that is backwards compatible.

And it really works that way.. almost. You really can take an existing class (defined with `class`) and change it into a record (defined with `record`) and all existing code continues to work just fine. However, this means all your properties now neccessarily get an accessor function that is named after the property. And that is a problem for LocalDate specifically: It already has accessors and they are named e.g. `getYear()`. Not `year()`. That means if LocalDate were to be rewritten as a record, one of two very nasty options must be chosen:

* Break backwards compatibility: As part of upgrading code you must change all calls to `.getYear()` into calls to `.year()`. It's a total ecosystem split: Every dependency you use comes in 2 flavours, one with calls to getYear and one with year, and you must use the right ones. This is truly catastrophic.

* Have both methods. There's year() and also getYear() and they do the same thing. Which is the lesser evil by far, but it makes very clear that LocalDate predates `record`. Contrast to ArrayList: It is not all that obvious that ArrayList predates generics. It does, but if you were to design ArrayList from scratch after generics are introduced you'd probably make the same code. Maybe the signature of `remove` would have been `remove(T)` instead of the current `remove(Object)`.

Instead, obviously then, the best choice is to not make it a record. And that's my point: The best possible (possibly here perfection is the enemy of good, but, I'd have done it differently) way to deploy records would have included some way for localdate to turn into a record without the above dilemma.

Perhaps simply a way to explicitly write your accessors with some marker to indicate 'dont generate the default `year()` - THIS is the accessor for it'.

Had that feature been part of record, then LocalDate could have turned into one in a way that you can't really tell.