Updated document on data classes and sealed types

Kevin Bourrillion kevinb at google.com
Thu Mar 7 21:52:14 UTC 2019

On Thu, Mar 7, 2019 at 12:47 PM Brian Goetz <brian.goetz at oracle.com> wrote:

But, there’s still a reason to allow overriding accessors — mutable types
> which don’t provide unmodifiable views — arrays being the obvious case.

Okay, mutable field types happen, and I can't think of any other reasonable
approach besides allowing accessor overrides.

> There’s another consideration, too.  We considered outlawing overriding
> the equals/hashCode method.  This goes a long way towards enforcing the
> desired invariants, but again seems pretty restrictive.

Yes, it's restrictive, and restrictiveness is what's great about records.
Is this decision based on compelling use cases or on "seems pretty

> And, having an irregular set of rules about what can be overridden and
> what can’t (e.g., no to equals, yes to toString), seems likely to (a) make
> the feature harder to learn/undersatnd and (b) lead to lots more “why can’t
> I, I just want to ….” complaints.  Better to have an all-or-nothing
> treatment of overriding,

I like predictable rules, but this doesn't seem like a *major* consideration
to me. If one has good use cases and the other doesn't, a different rule
for each may be justified.

> Normalization can happen on single arguments or multiple:
>      record Person(String name) {
>           public Person {
>                name = name.toUpperCase();
>           }
>      }
> (Note that I’m mutating the parameter, which will then get written to the
> field.)

I'm a bit relieved to hear this. The document seemed to imply that you
would assign to the field, then later the remaining fields that weren't DA
would be set from the remaining parameters. I think parameter reassignment
is superior because there are never two versions of the data in scope at
the same time. (I think the argument *against* parameter reassignment is
mainly that it's heresy.)

Rational numbers are a great example; Guy raised these earlier as well.
> Where rationals challenge the model here is: the user provided a state
> vector of (4, 2), but the final state of the object is (2, 1).  This is at
> odds with the following desirable-seeming invariant:
>      record Foo(int x, int y)
>      assert new Foo(1, 2).x() == 1
>      assert new Foo(1, 2).y() == 2
> That is, if we normalize any fields in the ctor, then the relationship of
> “the constructor argument x and the accessor x() are referring to the same
> state” appears to be severed.

Desirable-*seeming*, maybe, but this invariant is *not* actually desirable
for a Rational class. I'm not sure whether this is what you are also saying.

(Apart from that Rational class, one could have a "Fraction" class that
does behave that way, but *that* is the case that similar enough to
IntIntPair as to be not that interesting for our current discussion. And if
it has an equality method that returns true for 1/2 and 2/4 that method
should *not* be called equals. I don't think that is what either Peter or
Fran is after here; they differ only in what they want the private internal
representation to be, for performance reasons.)

> There are two possible solutions I see to this. The first is to permit
> some kind of derived-field mechanism, preferably lazy. Then, Fraction’s
> constructor would save a thunk for producing the reduced form, and refer to
> that thunk in the numerator() and denominator() accessors, but ignore it in
> the #mul method so that we don’t pay the cost of reducing unless we want it
> (here, imagine reducing a Fraction is more expensive than allocating a
> thunk).

> The stricture against derived fields was probably the hardest choice
> here.  On the one hand, strictly derived fields are safe and don’t
> undermine the invariants; on the other, without more help from the language
> or runtime, we can’t enforce that additional fields are actually derived,
> *and* it will be ultra-super-duper-tempting to make them not so.  (I don’t
> see remotely as much temptation to implement maliciously nonconformant
> accessors or equals methods.)  If we allowed additional fields, we would
> surely have to lock down equals/hashCode.

I still want to understand what the scenario we're worried about here is.
Whether the value is computed later using a "lazy fields" feature or
eagerly in the constructor, only the record's state is in scope, and sure,
people *can* shoot themselves in the foot by calling out to some static
method and getting some result not determined by the parameters, but why is
this worth worrying about? Do you have an example that's both dangerous and
tempting? (Sorry if you've said it before.)

> On Fri, Mar 1, 2019 at 12:28 PM Brian Goetz <brian.goetz at oracle.com
> <mailto:brian.goetz at oracle.com>> wrote:
> > I've updated the document on data classes here:
> >
> >      http://cr.openjdk.java.net/~briangoetz/amber/datum.html <
> http://cr.openjdk.java.net/~briangoetz/amber/datum.html>
> >
> > (older versions of the document are retained in the same directory for
> > historical comparison.)
> >
> > While the previous version was mostly about tradeoffs, this version
> > takes a much more opinionated interpretation of the feature, offering
> > more examples of use cases of where it is intended to be used (and not
> > used).  Many of the "under consideration" flexibilities (extension,
> > mutability, additional fields) have collapsed to their more restrictive
> > form; while some people will be disappointed because it doesn't solve
> > the worst of their boilerplate problems, our conclusion is: records are
> > a powerful feature, but they're not necessarily the delivery vehicle for
> > easing all the (often self-inflicted) pain of JavaBeans.  We can
> > continue to explore relief for these situations too as separate
> > features, but trying to be all things to all classes has delayed the
> > records train long enough, and I'm convince they're separate problems
> > that want separate solutions.  Time to let the records train roll.
> >
> > I've also combined the information on sealed types in this document, as
> > the two are so tightly related.
> >
> > Comments welcome.

Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb at google.com

More information about the amber-spec-observers mailing list