<div dir="auto"><div dir="auto">It seems like the problem is the flexibility combined with the ease of use.</div><div dir="auto"><br></div><div dir="auto">Fundamentally, if you represent *mutation* using records you are bound to have mismatches between different levels of the application.</div><div dir="auto"><br></div><div dir="auto">Trying to mutate a record in a db using Java's record is bound to create problems. </div><div dir="auto"><br></div><div dir="auto">Similarly, trying to respect db record (whose identity is a *specific column/list of columns*) as data-as-identity constructs (record/carriers) will also have mismatches.</div><div dir="auto"><br></div><div dir="auto">No amount of language level features will solve this.</div><div dir="auto"><br></div><div dir="auto">To bridge the gap you would need to wrap the API with some construct that make the identity immutable.</div><div dir="auto"><br></div><div dir="auto">Until now the problem is not too bad because to "make a stupid mistake" takes effort, but with Withers it becomes easy. To solve this problem without introducing new languages level type (adding language level annotation to specific fields is something I would call a new language level type) we would need to do something like "wither-validator":</div><div dir="auto"><br></div><div dir="auto">record DbRecord(long id, String f0, String f1, ...) {</div><div dir="auto"> withCheck(DbRecord newValue) {</div><div dir="auto"> if (newValue.id() != <a href="http://this.id">this.id</a>()) throw ...</div><div dir="auto"> }</div><div dir="auto">} </div><div dir="auto"><br></div><div dir="auto">Which the JVM calls automatically after the wither expression ends but before it returns the value. So</div><div dir="auto"><br></div><div dir="auto">myRecord with { id+1 }</div><div dir="auto"><br></div><div dir="auto">Will throw runtime exception. I'm not sure how worth this feature is.</div><div dir="auto"><br></div><div data-smartmail="gmail_signature" dir="auto"><div dir="ltr">Holo The Wise Wolf Of Yoitsu</div></div><br><div class="gmail_quote" dir="auto"><div dir="ltr" class="gmail_attr">On Mon, 26 Jan 2026, 18:26 Brian Goetz, <<a href="mailto:brian.goetz@oracle.com" target="_blank" rel="noreferrer">brian.goetz@oracle.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
> If we conceive of carrier classes as mostly "record-like but..." Then <br>
> I think what we tell people to do won't have changed. It's really just <br>
> that there's a new "wrong" thing that can be done that will be <br>
> tempting to do.<br>
<br>
The semantic description is that a carrier class / component class / <br>
data class (shed to be painted later) has a complete, canonical, nominal <br>
description of its state. IOW, that the carrier _is_ the data, just <br>
like records -- its just you get more flexibility in representation, aka <br>
"more rope".<br>
<br>
The question of this thread is, "is this too much rope".<br>
</blockquote></div></div>