<div dir="auto"><div>Wonderful news!<div dir="auto"><br></div><div dir="auto">Constant Patterns cannot arrive soon enough. There are several bugs that I spent time uprooting in my code (already reported here on the mailing list) that Constant Patterns would have saved me from. Once Constant Patterns go live, this shield we call Exhaustiveness Checking will finally become an air-toght force-field -- there will be no more cracks or gaps for edge cases to sneak through if you model your domain in the type system (except nulls, but that'll change once the nullness jep goes live).</div><div dir="auto"><br></div><div dir="auto">And the Pattern Assignment JEP looks great. I do have questions about null and how that will play out while we still don't have the nullness JEP. I'll hold them for now, assuming now is an inappropriate time to raise them.</div><div dir="auto"><br></div><div dir="auto">Thanks again!</div><div dir="auto">David Alayachew</div><br><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Fri, Jan 9, 2026, 6:08 PM Gavin Bierman <<a href="mailto:gavin.bierman@oracle.com">gavin.bierman@oracle.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Dear spec experts,<br>
<br>
Happy New Year to you all! We thought this was a good time to share you some of the thinking regarding Amber features for 2026.<br>
<br>
Currently we have one feature in preview - Primitive Patterns. We’d love to get more feedback on this feature - please keep kicking the tires!<br>
<br>
We plan two new features in the near term. Draft JEPs are being worked on and will be released as soon as possible. But here are some brief details while you are waiting for the draft JEPs (in the name of efficiency, *please* let's save discussion for that point).<br>
<br>
## PATTERN ASSIGNMENT<br>
<br>
Pattern matching is an inherently partial process: a value either matches a pattern, or it does not. But sometimes, we know that the pattern will always match; and we are using the pattern matching process as a convenient means to disassemble a value, for example:<br>
<br>
    record ColorPoint(int x, int y, RGB color) {}<br>
<br>
    void somethingImportant(ColorPoint cp) {<br>
        if (cp instanceof ColorPoint(var x, var y, var c)) {<br>
            // important code<br>
        }<br>
    } <br>
<br>
The use of pattern matching is great, but the fact that we have to use it in a conditional statement is annoying. It’s clutter, and worse, it is making something known by the developer and compiler look as if it were unknown; and, as a consequence, the important code ends up being indented and the scope of the pattern variables is limited to the then block. The indent-adverse developer may reach for the following, but it’s hardly better:<br>
<br>
    void somethingImportant(ColorPoint cp) {<br>
        if (!(cp instanceof ColorPoint(var x, var y, var c))) {<br>
            return;<br>
        }<br>
        // important code<br>
    } <br>
<br>
The real issue here is that both the developer and the compiler can see that the pattern matching is not partial - it will always succeed - but we have no way of recording this semantic information. <br>
<br>
What we really want is a form of assignment where the left-hand-side is not a variable but a **pattern**. So, we can rewrite our method as follows:<br>
<br>
    void somethingImportant(ColorPoint cp) {<br>
        ColorPoint(var x, var y, var c) = cp;    // Pattern Assignment!<br>
        // important code<br>
    } <br>
<br>
Luckily, the spec already defines what it means for a pattern to be unconditional (JLS 14.30.3), so we can build on this <br>
<br>
    void hopeful(Object o) {<br>
        ColorPoint(var x, var y, var c) = o; // Compile-time error!<br>
    }<br>
<br>
<br>
## CONSTANT PATTERNS<br>
<br>
Another common pattern (sic) with pattern matching code is where we want to match a particular pattern but only for a certain value, for example:<br>
<br>
    void code(Shape s) {<br>
        switch (s) {<br>
            case Point(var x, var y) when x == 0 && y == 0 —> { // special code for origin <br>
            }<br>
            case Point(var x, var y) -> { // code for non-origin points<br>
            }<br>
            ...<br>
        }<br>
        ...<br>
    }<br>
<br>
It’s great that our pattern `switch` allows us to have separate clauses for the point on the origin and the other points. But it’s a shame that we have to use a `when` clause to specify the constant values for the origin point. This makes code less readable and is not what we would do if we were thinking of the code more mathematically. What we want to do is inline the zero values into the pattern itself, i.e.<br>
<br>
    void code(Shape s) {<br>
        switch (s) {<br>
            case Point(0, 0) -> { // special code for origin <br>
            }<br>
            case Point(var x, var y) -> { // code for non-origin points<br>
            }<br>
            ...<br>
        }<br>
        ...<br>
    }<br>
<br>
In other words, we’d like to support a subset of constant expressions, including `null`, to appear as nested patterns. We think that will lead to even more readable and concise pattern matching code and, from a language design perspective, allows us to address the somewhat awkward separation of case constants and case patterns, by making (almost) everything a pattern.<br>
<br>
We have other new Amber features in the pipeline, but we propose to prioritize these two features, along with the primitive patterns feature already in preview. Please look out for the announcements of draft JEPs when they arrive - as always, we value enormously your help in designing new features for our favorite programming language!<br>
<br>
Wishing you a happy and successful 2026!<br>
Gavin</blockquote></div></div></div>