Data classes
Stephen Colebourne
scolebourne at joda.org
Wed Nov 8 19:39:36 UTC 2017
Like Mark and Remi, I think nullability is a key missing element.
While a language-wide approach to nullability would be nice, it isn't
needed to meet the need here. I agree with the points being made that
null interacts with hashCode, equals and toString, as well as
construction and getters. Data classes can't avoid dealing with null.
A couple of options:
Option1: All data class fields must be non-null
This is nice and simple. The constructor would validate all fields are
non-null. Optional<T> would be used for optional things. There would
be no impact on the wider language, its just that when you call a
getter you know that the result is non-null and doesn't need to be
null-checked.
Option 2: Fields on data classes can be marked as non-null or nullable
This is more complex. It could be via annotation or some other
syntactic form. It triggers the constructor to perform validation as
necessary, and alters the hashCode/equals/toString generation. But as
with option 1, there is no impact on the wider language.
If Optional<T> is going to be a value type at some point, then I think
option 1 is the simplest and neatest, and punts on nullability as a
general language feature, which is a good thing at this point.
But I definitely think that there is no need to do full nullity
propagation. I can say this with confidence because I have 3+ years
experience with a codebase where all data-like classes (beans) expose
only non-null values (in Java 8 where there is no nullity
propagation). While this is seemingly a small step, it turns out that
it vastly simplifies the rest of the codebase, as you tend to
completely forget null is a problem in the language. ie. there would
be no compiler protection against checking for null on the output of a
data-like class, but in practice that doesn't matter.
See https://github.com/OpenGamma/Strata
In general though, I like data classes. Devil in the detail and all that :-)
Stephen
On 8 November 2017 at 16:29, Mark Raynsford <mark at io7m.com> wrote:
> On 2017-11-03T13:19:09 +0100
> forax at univ-mlv.fr wrote:
>>
>> Yes, the point is about encapsulation, boundaries, as you have written.
>> We used to insert Objects.requireNonNull at the start of public methods to validate preconditions, given that the primary constructor of a data class is now generated, the question is how to tell the compiler to generate those precondition for me.
>
> Having played around with the prototype today, I have to say that I
> think Rémi might be right!
>
> It's what I think of as the Haskell effect: When you have a language
> with very terse syntax, every single piece of boilerplate you have to
> write seems a lot worse than it otherwise would. If you take a look at
> a typical Haskell file, it somewhat ironically feels as though there's
> quite a bit of boilerplate (typeclass instances, module export lists,
> matching on record values, signatures to some extent) because the rest
> of the language requires so few keystrokes.
>
> Having used data classes a little, I can see that I'm now almost never
> going to use the default constructor because I always want to insert
> calls to Objects.requireNonNull(...). Those have become the new
> mildly annoying boilerplate (and yet I'm used to having to write them
> over and over by hand in normal classes today).
>
> --
> Mark Raynsford | http://www.io7m.com
>
More information about the amber-spec-observers
mailing list