Records -- current status
brian.goetz at oracle.com
Tue Mar 27 13:04:09 UTC 2018
> > Extension
> Do I understand it right that you are proposing that Records cannot
> inherit normal classes, while abstract records can be inherited by
> normal classes?
More restrictive than that:
- records can extend abstract records, or Object (really, AbstractRecord)
- that's it.
There are two primary drivers why non-abstract records shouldn't be
extended by something else (record or not):
- Identity anomalies. If S extends R, where R is a record, then ctor
composed-with dtor is not an identity on R. That means if someone does:
case R(R_ARGS) -> new R(R_ARGS)
they may think they are cloning, but in fact they are decapitating.
(Even if S has no additional state over R, it still has typestate that
- Equality anomalies. If S can extend R, and S has state that wants
to participate in equals/hashCode, and therefore wants to override
equals, this may violate the symmetry or transitivity of equals.
The current notion of abstract records avoids both of these because it
has no equality (abstract records reabstract equals), and has no
constructors, so ctor \compose dtor is meaningless on abstract records.
> Is a decision to make class be a record a binding decision over long
We intend that there should be a source- and binary- compatible
refactoring between a record and an equivalent class.
The class to record direction is the one that is immediately
interesting, since people have source bases full of classes they'd like
to turn into records. This is OK as long as the members the class
already has (constructor, equals) conform to the semantics of their
record equivalents, and the author is OK with the class being final and
The other direction is likely to be less common, but also important; it
is analogous to refactoring an enum to a class that uses the type-safe
enum pattern, which happens once in a while when you hit the limits of
what you can do with an enum/record. But given that the goal all along
is to have records be "just macros for corresponding classes", this
should be doable.
Where the decision is binding is when you take on a specific class
record Point(int x, int y);
If you want to add a `z` to this, you're venturing onto the ice.
Existing code may assume the existence of an XY constructor or
deconstructor; we can probably handle this via adding additional
explicit ctor/dtors. But existing code may also depend on the
behavioral assumption that equality of points is based on x and y. So
the record <--> class refactoring is practical, but the record <-->
different record refactoring is dicier. (That said, the sweet spot for
records is when they are used within a maintenance boundary, where you
can find all the uses. So this might be OK too.)
> Given that records cannot inherit from normal classes, but normal
> classes can inherit from records AND
> names are important part of source level compatibility, I'm torn on
> abstract records.
With the more restricted understanding, that normal classes cannot
extend records, does this change your position?
More information about the amber-spec-observers