Amber features 2026
Gavin Bierman
gavin.bierman at oracle.com
Fri Jan 9 23:08:05 UTC 2026
Dear spec experts,
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.
Currently we have one feature in preview - Primitive Patterns. We’d love to get more feedback on this feature - please keep kicking the tires!
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).
## PATTERN ASSIGNMENT
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:
record ColorPoint(int x, int y, RGB color) {}
void somethingImportant(ColorPoint cp) {
if (cp instanceof ColorPoint(var x, var y, var c)) {
// important code
}
}
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:
void somethingImportant(ColorPoint cp) {
if (!(cp instanceof ColorPoint(var x, var y, var c))) {
return;
}
// important code
}
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.
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:
void somethingImportant(ColorPoint cp) {
ColorPoint(var x, var y, var c) = cp; // Pattern Assignment!
// important code
}
Luckily, the spec already defines what it means for a pattern to be unconditional (JLS 14.30.3), so we can build on this
void hopeful(Object o) {
ColorPoint(var x, var y, var c) = o; // Compile-time error!
}
## CONSTANT PATTERNS
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:
void code(Shape s) {
switch (s) {
case Point(var x, var y) when x == 0 && y == 0 —> { // special code for origin
}
case Point(var x, var y) -> { // code for non-origin points
}
...
}
...
}
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.
void code(Shape s) {
switch (s) {
case Point(0, 0) -> { // special code for origin
}
case Point(var x, var y) -> { // code for non-origin points
}
...
}
...
}
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.
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!
Wishing you a happy and successful 2026!
Gavin
More information about the amber-spec-experts
mailing list