About the possibility of using JEP468 to inspire optional fields in records for domain contracts modeling.

david Grajales david.1993grajales at gmail.com
Tue Mar 11 18:28:24 UTC 2025


Hi Brian. Thanks for the answer. I totally agree about using with with
expressions for this is a bad idea, I just made use of it for explanation
purposes and agree this should be properly designed.

I am happy to know this matter is on the table, even if it takes quite some
time to get there.

best regards and wishes to all people involved in the evolution of the java
platform.

El mar, 11 mar 2025 a la(s) 12:23 p.m., Brian Goetz (brian.goetz at oracle.com)
escribió:

> The problem you are grappling with here is an important one --
> optionality.  What you really want to say is that some of the components of
> your record are required (like name), and others are optional, and you are
> using the convention of null to mark which components are not present.  And
> you would like for the notion of which components are optional to be part
> of the programming model, so users and compilers alike can ensure correct
> use.  And, you observe that Java is getting nullity control, perhaps those
> can be used to capture optionality in the type system as well.
>
> This is all reasonable, and similar ideas have been discussed.  I think it
> is safe to say there are two camps here: one that finds the use of nullity
> control to capture optionality to be a pragmatic approach, and another that
> views it as mixing concerns.  There are arguments on both sides of this
> debate (we don't have to have it again here), but I think it's fair to say
> that this is one of the ideas that is on the table.  (This gets especially
> interesting if we are ever able to instantiate objects nominally, because
> then you could say `new Foo(a:1, z: 26)`, and omit b-y if they are
> optional.  (And we're not going to discuss this possibility again for quite
> some time; there are a lot of higher-priority things between here and the
> possibility of there.))
>
> The topic of using (abusing? distorting?) `with` as a way to backdoor
> optional parameters into the language has come up a number of times, and
> we've consistently said "these are not the droids you are looking for."  So
> while we understand the goal (instantiating objects without having to
> specify all non-required parameters), and we agree that the goal is
> valuable, it is pretty clear that this is the wrong way to get there, and
> that the many suggestions to use `with` in this manner are an attempt at
> shortcutting the language-design process to get it sooner by piggybacking
> it on something else.  But we don't work this way.  If this is a feature
> worth having, it is feature worth properly designing.
>
> Cheers,
> -Brian
>
>
>
> On 3/11/2025 10:48 AM, david Grajales wrote:
>
> Hi Amber team. I would like to share some thoughts based on real use cases
> I am dealing with at work.
>
>
> I know is very likely you have already thought about something like this and I don't know if this would be the best solution for the use case presented.
>
> My intention is not to propose this as "the solution" but instead just present a personal use-case based on my actual job and a naive solution that crossed my mind in the first 15 minutes.
>
> So please pay more attention to the use case and "the problem" rather than the proposed "solution" which is actually just a mean to explain the problem
>
>
> Nowadays to create a new record object we must set the value to all it
> fields, even the ones that might be null.
>
> record User (String name, String email){}var userWithoutEmail = new User ("name", null)
>
> This is good since it forces us to set all fields to a valid state and
> null can be a valid state. This is useful for things like JSON
> serialization; null fields in JSON are usually not serialized, which saves
> some bandwidth, in very large JSON structures that only have an small set
> of mandatory fields, this is very common in banks that happens to be
> international, since they usually use the same Core for all countries but
> each country may have different requirements (for example in some countries
> it's mandatory for people to provide 2 lastnames but in other countries
> usually you only have one lastname).
>
> To achieve this I usually do the opposite of withers, let me introduce you
> to the "withouts"
>
> record User (String name, String email){     public static withoutEmail(String name){           return new User(name, null);   }}var userWithoutEmail = User.withoutEmail(name);
>
> The example is very basic for explanatory purposes and for a record with
> only 2 fields this can be an overkill, but for bigger records it makes a
> lot of sense, specially if only few fields between dozens are actually
> mandatory.
>
> Why not use a class instead? Serialization. records' serialization uses
> the record constructor, which means it's safer since you can make format
> and safety validations in the data before the record is built.
>
> nowadays to make sure all the mandatory fields are set, I do something
> like this.
>
> record User (String name, String email){
> User{
> if(name == null)
> throw new IllegalArgumentException("name field it's mandatory");
> }
> }
>
>
> With derived record creation (or something equivalent but for direct
> creation) and nullability it would be possible and very handy to be able to
> declare optional fields that would compile to null (or zero in case of
> primitives)
>
>
> *Please ignore the straw man syntax from here.*
>
> record User (String name!, String email? ){}User userWithoutEmail with { name : "name"}
>
> This would make this feature in java to behave similar to TypeScript's
> interfaces, which are used to model data
>
> export interface User {   name: String!   email: String?}
>
>
> To me one of the most useful use cases of this would be for writing
> unitary tests and mocks.
>
> when writing tests sometimes you want to test the behaviour of your
> contracts (the domain objects) when they carry only the bare required
> fields, if one has very large json objects to try out but only a small set
> of mandatory fields usually it's easier to write down the json string and
> pass it to jackson or gson, with this we could use the domain object
> directly.
>
>
> Regular test if the domain object has many optional fields
>
> record Message (String id, String document, String name, String lastname, String email.... (another 20 fields)){}
>
> var request = """{  id: "XXXXXXX",  document: "NNN-NNNNN"}"""
>
> var message = gson.fromJson(request, Message.class);var res = method2Test(message);// put your favorite assertion here//
>
>  this has the issue you don't have help from the compiler in case you want to represent different scenarios (formatting data, invalid fields, etc)
>
> this is why I usually do "whitouts" for this kind of records.
>
> record Message (String id, String document, String name, String lastname, String email.... (another 20 fields)){
>
>   public Static Message minimalRequest(String id, String document){
>
>      return new Message (id, document, lastname, email, null, null...);
>
>    // so I have to write all those nulls once
>
>    }
>
> }
>
> var request = Message.minimalRequest(.....);
>
> var res = method2Test(message);
>
> // put your favorite assertion here//
>
>
> With optional fields in records there could be changed for something like
> this.
>
> record Message (String id, String document, String name?, String lastname?, String email? .... (another 20 nullable fields)){}
> Message request  with {id: "XXXXXXXX"; document: "NNN-NNNNNN"}var res = method2Test(message);// put your favorite assertion here//
>
> I hope this presented use-case it's useful
>
> Best regards!
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20250311/641787e9/attachment-0001.htm>


More information about the amber-dev mailing list