Re: Records — Dealing with nullable values

Stephen Colebourne scolebourne at joda.org
Sun Dec 15 01:07:45 UTC 2019


As a data point, we at OpenGamma follow the get/optional pattern 100%.
We never return null from a data object, always optional. And we never
use Optional as the field value. And very rarely is Optional used as a
method/constructor parameter, because doing so is very unfriendly to
your caller.

>From a quick search:
Subsystem a: 1035 beans which contain 4895 properties, of which 400
properties follow the get=optional pattern (~8%)
Subsystem b: 1124 beans which contain 2694 properties, of which 126
properties follow the get=optional pattern (~5%)

Records are clearly not beans, they are effectively something new
(nominal tuples) that Java devs will have to learn not to overuse.
(And I suspect there will be a lot of overuse). ie. Arash, I'd
question whether its really the right choice to switch from Lombok to
records, despite the shorter syntax.


Brian, I still think that there is the opportunity to build on
records, onion-like, to handle bean use cases. ie. allowing a class to
declare its public state as a record, but keeping that record separate
from the main API of the class. eg with some examplar syntax:

public class Person {
 public record(String name, Gender gender);
 private String summary;  // additional non-record fields for whatever
purpose is necessary
 // constructor/equals/hashCode/toString/accessors delegate to record
but can be overridden with none of the restrictions records have
 // thus this is OK, package scoped and optional
 Optional<Gender> gender() { return ofNullable(record.gender()); }
 // and setters too if desired
 public void setName(String name) { record = new record(name, record.gender());
}

ie. whenever the formal state is needed, code can use `person.record`
instead of `person`. I suspect much of this would work anyway if a dev
wrote a nested record of Person and a public field named `record`, but
the idea is that extra syntax sugar here would integrate the class
with the record more closely.

Stephen


On Sat, 14 Dec 2019 at 22:39, Brian Goetz <brian.goetz at oracle.com> wrote:
>
> Records are _transparent, shallowly immutable containers for their
> state_.  So either the record holds a Gender and exposes that as the
> API, or it holds an Optional<Gender>, and exposes that.  If you are
> using what is essentially a macro generator (like Lombok), I'm sure it
> has a hundred knobs you can twiddle to represent your favorite
> patterns.  But that's not what records are -- records are _nominal
> tuples_ (just as functional interfaces are _nominal function types_.)
>
> I get why you are seeking a nulls-in, Optional-out protocol -- you're
> trying to follow Postel's law.  But if you really want to treat "no
> gender" as a valid point in the domain, then just make a record with an
> Optional<Gender> component, and push the `Optional.ofNullable()` to the
> caller (or, provide an overloaded constructor that does it for them.)
> But I would still use this pattern sparingly; the majority of uses I see
> of Optional in domain models are gratuitous.


More information about the amber-dev mailing list