<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
</head>
<body style="overflow-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;">
Thanks for your email. An instanceof statement/pattern-let statement is firmly on our roadmap (i.e. the first solution you suggest).
<div><br>
</div>
<div>Gavin<br id="lineBreakAtBeginningOfMessage">
<div><br>
<blockquote type="cite">
<div>On 28 Jul 2025, at 09:08, Aaryn Tonita <atonita@proton.me> wrote:</div>
<br class="Apple-interchange-newline">
<div>
<div style="font-family: Arial, sans-serif; font-size: 14px;">In my organization we have settled upon an architecture that leverages sealed interfaces with records implementing those interfaces to build up our domain model. The sealed interfaces enable the
needed level of polymorphism and the immutable records with canonical constructors ensure that our business invariants are clear and easily enforced. When transitioning between various states (the implementing records) we can easily switch on the instance
of a sealed interface and pattern match the records to easily build the next state. We also similarly use the design when mapping to DTO's or database entities.</div>
<div style="font-family: Arial, sans-serif; font-size: 14px;"><br>
</div>
<div style="font-family: Arial, sans-serif; font-size: 14px;">A benefit of the pattern matching approach here arises on iteration of the design. As we add features to the application, we will add additional fields to the records and the deconstruction sites
need to be updated with the new field. Unlike with JavaBeans, it doesn't happen that we fail to update such a state transition or mapping and create a bug by forgetting to carryover the new field: you cannot compile the code until you add the field to the
record deconstruction. It can happen that the field gets marked as ignored (with the _ pattern) generally with a comment.</div>
<div style="font-family: Arial, sans-serif; font-size: 14px;"><br>
</div>
<div style="font-family: Arial, sans-serif; font-size: 14px;">A nuisance arises however when you want to deconstruct an instance of a record instead of a instance of a sealed interface because patterns are only available in case arms and with instanceof. The
nuisance means that you end up with code such as:</div>
<div style="font-family: Arial, sans-serif; font-size: 14px;"><br>
</div>
<div style="font-family: Arial, sans-serif; font-size: 14px;"><span style="font-family: Menlo, Consolas, Courier New, monospace;">public class PatternDeconstruction {</span>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> record Foo() {}</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> record Bar() {}</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> record FooBar(Foo foo, Bar bar) {}</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> record OtherFooBar(Foo foo, Bar bar) {}</span></div>
<div><br>
</div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> interface FooBarSink {</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> void sink(Foo foo);</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> void sink(Bar bar);</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> }</span></div>
<div><br>
</div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> OtherFooBar map(FooBar fooBar) {</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> Objects.requireNonNull(fooBar);</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> if (fooBar instanceof FooBar(var foo, var bar)) {</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> return new OtherFooBar(foo, bar);</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> } else {</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> throw new AssertionError("Unreachable.");</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> }</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> }</span></div>
<div><br>
</div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> OtherFooBar map2(FooBar fooBar) {</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> return switch (fooBar) {</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> case FooBar(var foo, var bar) -> new OtherFooBar(foo, bar);</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> };</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> }</span></div>
<div><br>
</div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> void sink(FooBarSink sink, FooBar fooBar) {</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> Objects.requireNonNull(fooBar);</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> if (fooBar instanceof FooBar(var foo, var bar)) {</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> sink.sink(foo);</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> sink.sink(bar);</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> }</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> }</span></div>
<span style="font-family: Menlo, Consolas, Courier New, monospace;">}</span></div>
<div style="font-family: Arial, sans-serif; font-size: 14px;"><span><br>
</span></div>
<div style="font-family: Arial, sans-serif; font-size: 14px;"><span>A choice must be made between giving up on the deconstruction or a choice between an if or a switch. The if with instanceof is especially ugly because of the "unreachable" (null guarding) branch.
This doesn't occur on a sink type method, it just confusingly looks like the branch might not always trigger. <span>The switch instead often creates two levels of indentation (not shown here).
</span>However, in all cases static analysers complain about this code because it is never conditional.</span></div>
<div><br>
</div>
<div style="font-family: Arial, sans-serif; font-size: 14px; background-color: rgb(255, 255, 255);">
I was hoping there would be JEP for a bare pattern finding or a method parameter pattern binding, something that would allow one of</div>
<div style="font-family: Arial, sans-serif; font-size: 14px; background-color: rgb(255, 255, 255);">
<br>
</div>
<div style="font-family: Arial, sans-serif; font-size: 14px; background-color: rgb(255, 255, 255);">
<span style="font-family: Menlo, Consolas, Courier New, monospace;"> OtherFooBar map3(FooBar fooBar) {</span>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> FooBar(var foo, var bar) = fooBar;</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> return new OtherFooBar(foo, bar);</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> }</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> </span>
</div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> OtherFooBar map4(FooBar(var foo, var bar)) {</span></div>
<div><span style="font-family: Menlo, Consolas, Courier New, monospace;"> return new OtherFooBar(foo, bar);</span></div>
<span style="font-family: Menlo, Consolas, Courier New, monospace;"> }</span></div>
<div style="font-family: Arial, sans-serif; font-size: 14px; background-color: rgb(255, 255, 255);">
<br>
</div>
<div style="font-family: Arial, sans-serif; font-size: 14px; background-color: rgb(255, 255, 255);">
but such a JEP doesn't seem to exist. It feels natural to me that such a feature should be present but I am unsure if my intuition is coming from my pattern matching experience in other languages or if any Java developer would naturally share the intuition.
In any case, I am hoping you have such a feature on the radar, but I am aware of the derived record creation and would certainly vote for prioritizing that just to give you some anecdata on the practical impacts of the workarounds between the two. We are eagerly
awaiting the derived record creation.</div>
<div style="font-family: Arial, sans-serif; font-size: 14px;" class="protonmail_signature_block protonmail_signature_block-empty">
<div class="protonmail_signature_block-user protonmail_signature_block-empty"></div>
<div class="protonmail_signature_block-proton protonmail_signature_block-empty"></div>
</div>
</div>
</blockquote>
</div>
<br>
</div>
</body>
</html>