From archie.cobbs at gmail.com Tue Jan 13 22:56:51 2026 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Tue, 13 Jan 2026 16:56:51 -0600 Subject: Amber features 2026 In-Reply-To: <1C8344A8-B712-422D-9F66-FB4ED89373FC@oracle.com> References: <1C8344A8-B712-422D-9F66-FB4ED89373FC@oracle.com> Message-ID: [ This is in reply to https://mail.openjdk.org/pipermail/amber-spec-experts/2026-January/004306.html on amber-spec-experts. ] Hi Gavin, The "Pattern Assignment" and "Constant Patterns" ideas sound good to me. The "Pattern Assignment" idea is a natural way to extend pattern matching, which is motivated by the frequent need to declare variables to access the "variable components" in an instance of some object type. My question is: Wouldn't the same motivation apply to generic type parameters as well? Here's a trivial example. Suppose we have this class: public record Property(T value) { boolean has(T t) { return t == value; } } and we want to write a method to check that a list of Property's are well-behaved. Here's what we'd LIKE to do, which is use "Pattern Assignment" for the generic type variable: public void verifyHas(List> properties) { for (Property element : properties) { Property property = element; T value = property.value(); assert property.has(value); // no cast needed here! } } but here's what we HAVE to do today to avoid the unchecked cast: public void verifyHas(List> properties) { for (Property property : properties) { verifyHas(property); } } // Ugh. This method exists solely to declare so we can avoid an unchecked cast private void verifyHas(Property property) { T value = property.value(); assert property.has(value); } If we're going to add "Pattern Assignment" it seems like it would be reasonable for generic type variables to also benefit. Cheers, -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Wed Jan 14 02:33:12 2026 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 13 Jan 2026 21:33:12 -0500 Subject: Amber features 2026 In-Reply-To: References: <1C8344A8-B712-422D-9F66-FB4ED89373FC@oracle.com> Message-ID: While I totally understand why you would want to do that, I don't see the connection between pattern assignment and extending the type system to permit denotation of quantified or existential types?? I don't see any patterns in your example, only type manipulation. What you're saying is that you'd like a conversion from Foo to `\exist T . Foo`.? This is understandable, as wildcards are basically existentials already, and is just as safe as the the trick of calling an out-of-line generic method. But I just don't see the connection with pattern assignment?? It seems like what you really want is "generic variables", to go along with generic methods and classes? On 1/13/2026 5:56 PM, Archie Cobbs wrote: > [ This is in reply to > https://mail.openjdk.org/pipermail/amber-spec-experts/2026-January/004306.html > on amber-spec-experts. ] > > Hi Gavin, > > The "Pattern Assignment" and "Constant Patterns" ideas sound?good to > me. The "Pattern Assignment" idea?is a natural way to extend pattern > matching, which is motivated by the frequent need to declare variables > to access the "variable components" in an instance of some object type. > > My question is: Wouldn't the same motivation apply to generic type > parameters as well? > > Here's a trivial example. Suppose we have this class: > > ? ? public record Property(T value) { > ? ? ? ? boolean has(T t) { > ? ? ? ? ? ? return t == value; > ? ? ? ? } > ? ? } > > and we want to write a method to check that a list of Property's are > well-behaved. > > Here's what we'd LIKE to do, which is use "Pattern Assignment" for the > generic type variable: > > ? ? public void verifyHas(List> properties) { > ? ? ? ? for (Property element : properties) { > Property property = element; > ? ? ? ? ? ? T value = property.value(); > ? ? ? ? ? ? assert property.has(value);? // no cast needed here! > ? ? ? ? } > ? ? } > > but here's what we HAVE to do today to avoid the unchecked cast: > > ? ? public void verifyHas(List> properties) { > ? ? ? ? for (Property property : properties) { > ? ? ? ? ? ? verifyHas(property); > ? ? ? ? } > ? ? } > > ? ? // Ugh. This method exists solely to declare so we can avoid > an unchecked cast > ? ? private void verifyHas(Property property) { > ? ? ? ? T value = property.value(); > ? ? ? ? assert property.has(value); > ? ? } > > If we're going to add?"Pattern Assignment" it seems like it would be > reasonable for generic type variables to also benefit. > > Cheers, > -Archie > > -- > Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From ganapathibasamsetti at gmail.com Wed Jan 14 03:25:50 2026 From: ganapathibasamsetti at gmail.com (Ganapathi Vara Prasad) Date: Wed, 14 Jan 2026 08:55:50 +0530 Subject: Data Oriented Programming, Beyond Records Message-ID: Hello Brian, Thank you for thinking on this feature. I want to better understand the thought process behind marking all fields that are part of the component state instead of only the derived fields. Something like this: ``` class Point(int x, int y) { private final int x; private final int y; private final derived double norm; Point { norm = Math.hypot(x, y); } public double norm() { return norm; } // derived implementation of x and y accessors // derived implementation of equals, hashCode, toString } ``` -------------- next part -------------- An HTML attachment was scrubbed... URL: From ganapathibasamsetti at gmail.com Wed Jan 14 03:40:29 2026 From: ganapathibasamsetti at gmail.com (Ganapathi Vara Prasad) Date: Wed, 14 Jan 2026 09:10:29 +0530 Subject: Data Oriented Programming, Beyond Records In-Reply-To: References: Message-ID: Corrected Brian's email address. On Wed, 14 Jan, 2026, 8:55?am Ganapathi Vara Prasad, < ganapathibasamsetti at gmail.com> wrote: > Hello Brian, > > Thank you for thinking on this feature. I want to better understand the > thought process behind marking all fields that are part of the component > state instead of only the derived fields. Something like this: > > ``` > > class Point(int x, int y) { > private final int x; > private final int y; > private final derived double norm; > > Point { > norm = Math.hypot(x, y); > } > > public double norm() { return norm; } > > // derived implementation of x and y accessors > // derived implementation of equals, hashCode, toString > } > ``` > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Wed Jan 14 03:43:57 2026 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 13 Jan 2026 22:43:57 -0500 Subject: Data Oriented Programming, Beyond Records In-Reply-To: References: Message-ID: <0c047449-c92d-4b0a-9ccb-091a369741f4@oracle.com> First, a gentle reminder that I did ask "please, let's not discuss syntax."? It is way too early for that; we haven't even had a discussion on the value of the ideas yet.? But people can't help but obsess on syntax, so I'll answer, but please let's let this thread end here. Yes, we considered matching on name and type only.? There is nothing about that approach that makes it unworkable, but it is less reliable, and subjectively, seems to be more likely to feel "magic" or "action at a distance" to the Java developers we showed this to.? By comparison, the overhead of the `component` modifier is small; it is purely horizontal rather than vertical, and admits no question about which fields are component fields or not.? It also admits greater flexibility for users (under the implicit approach, we'd almost certainly want to error out if the names matched but the types didn't; with the explicit version, we can accept examples like the AlmostRecord in the writeup.) Basically: the value of the clarity seems to outweigh the value of the concision.? )(And, as you point out, a new modifier would still be needed for "not component" in that case.) On 1/13/2026 10:25 PM, Ganapathi Vara Prasad wrote: > Hello Brian, > > Thank you for thinking on this feature. I want to better understand > the thought?process behind marking all fields that are part of the > component state instead of only the derived fields. Something like this: > > ``` > class Point(int x, int y) { > ? ? private final int x; > ? ? private final int y; > ? ? private final derived double norm; > > ? ? Point { > ? ? ? ? norm = Math.hypot(x, y); > ? ? } > > ? ? public double norm() { return norm; } > > ? ? // derived implementation of x and y accessors > ? ? // derived implementation of equals, hashCode, toString > } > ``` -------------- next part -------------- An HTML attachment was scrubbed... URL: From ganapathibasamsetti at gmail.com Wed Jan 14 04:04:25 2026 From: ganapathibasamsetti at gmail.com (Ganapathi Vara Prasad) Date: Wed, 14 Jan 2026 09:34:25 +0530 Subject: Data Oriented Programming, Beyond Records In-Reply-To: <0c047449-c92d-4b0a-9ccb-091a369741f4@oracle.com> References: <0c047449-c92d-4b0a-9ccb-091a369741f4@oracle.com> Message-ID: Hi Brian, I might have worded question incorrectly, but it was about the idea of marking (which we need) on component vs derived fields. Why would we choose one over the other irrespective of the syntax used to achieve that? I still need to understand your response, but thanks for the response. On Wed, 14 Jan, 2026, 9:14?am Brian Goetz, wrote: > First, a gentle reminder that I did ask "please, let's not discuss > syntax." It is way too early for that; we haven't even had a discussion on > the value of the ideas yet. But people can't help but obsess on syntax, so > I'll answer, but please let's let this thread end here. > > Yes, we considered matching on name and type only. There is nothing about > that approach that makes it unworkable, but it is less reliable, and > subjectively, seems to be more likely to feel "magic" or "action at a > distance" to the Java developers we showed this to. By comparison, the > overhead of the `component` modifier is small; it is purely horizontal > rather than vertical, and admits no question about which fields are > component fields or not. It also admits greater flexibility for users > (under the implicit approach, we'd almost certainly want to error out if > the names matched but the types didn't; with the explicit version, we can > accept examples like the AlmostRecord in the writeup.) > > Basically: the value of the clarity seems to outweigh the value of the > concision. )(And, as you point out, a new modifier would still be needed > for "not component" in that case.) > > > On 1/13/2026 10:25 PM, Ganapathi Vara Prasad wrote: > > Hello Brian, > > Thank you for thinking on this feature. I want to better understand the > thought process behind marking all fields that are part of the component > state instead of only the derived fields. Something like this: > > ``` > > class Point(int x, int y) { > private final int x; > private final int y; > private final derived double norm; > > Point { > norm = Math.hypot(x, y); > } > > public double norm() { return norm; } > > // derived implementation of x and y accessors > // derived implementation of equals, hashCode, toString > } > ``` > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From john.r.rose at oracle.com Wed Jan 14 04:15:01 2026 From: john.r.rose at oracle.com (John Rose) Date: Tue, 13 Jan 2026 20:15:01 -0800 Subject: Amber features 2026 In-Reply-To: References: <1C8344A8-B712-422D-9F66-FB4ED89373FC@oracle.com> Message-ID: <982EF2DB-F7C9-48CC-AD3F-EF5063535A97@oracle.com> On 13 Jan 2026, at 18:33, Brian Goetz wrote: > While I totally understand why you would want to do that, I don't see > the connection between pattern assignment and extending the type > system to permit denotation of quantified or existential types?? I > don't see any patterns in your example, only type manipulation. > > What you're saying is that you'd like a conversion from Foo to > `\exist T . > Foo`.? This is understandable, as wildcards are basically > existentials already, and is just as safe as the the trick of calling > an out-of-line generic method. > > But I just don't see the connection with pattern assignment?? It > seems like what you really want is "generic variables", to go along > with generic methods and classes? I?ve wanted this sort of thing from time to time. I think of the ask as "local type variables", where the type variable is local to a block (tighter control than local to method or class/interface). But it would only be set via inference, not explicitly; in that it would be a narrower feature than type variables on methods or classes. The two other type variable occurrences (method, class) offer explicit specification as well as inference. But there is no occasion for explicit specification of a local type. If you have a type you want to use explicitly, you just declare the local with that type. Other kinds of variables (fields, not locals) also do not benefit from having their types inferred, for the same reason that the /var/ keyword is only accepted on locals. (Inferring a type for var on an API point is dangerously obscure, not worth the concision.) So, local type vars. The form Archie mentions is also the one that I have wondered about, these many years. ``` var x1a = foo(); // x1a has type inferred from foo() T1 x1b = foo(); // so does x1b; now it is denotable as T1 T1 x1c; // and now x1c has the same type too { x1a = x1b; x1b = x1c; x1c = x1a; } // types are the same Map x2 = bar(); // capturing g-type structure T3 x3a = baz(); List x3b = bat(); // checks result of baz is list of what x3a is T4 x4; // ERROR; must have an initializer to drive inference ``` This might allow some new types to become denotable, so maybe it?s dangerous. Maybe there is some useful sanitization move that could apply to type variables captured this way, as with var. But var definitely can capture non-denotables, despite sanitization. ``` var o1 = new Object() { int f; }; o1.f++; // field WHOOZIT.f o2a = new Object() { long f; static int Q; }; T2 o2b = o2a; // rather odd o2a.Q++; // static variable reference (deprecated syntax) o2b.Q++; // again? T2.Q++; // ERROR; unless T2 is a type alias instead of a type var ``` Oddly, the range of variation of such a type var is very narrow, since it can be driven only from one use site, the initialization. But it?s still a type var, if you squint, since the thing coming out of the initializer expression can have type vars mixed into it. Feature priority? Very low! It?s a "filling in the corners" move. No known important use cases. The use case I had was avoiding refactoring to a private generic method, because the body wanted to access some local vars in an enclosing scope. In the end, I think I just boxed the local vars in an array and moved on with the generic helper method. It did make the code more obscure, so having a local type var would have been an aid in readability. But it?s rare to want to name that type, and I can?t recall why I needed to. In other words, I am not asking for a JEP or RFE for this. Just laying out the case FTR, in case a use comes up later. Maybe the balance shifts if/when we get reified generics, since then there will be "more to capture". There, got it all off my chest. Thanks Archie for fellow-traveling. Now, back to 2026. ? John -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Wed Jan 14 08:39:55 2026 From: forax at univ-mlv.fr (Remi Forax) Date: Wed, 14 Jan 2026 09:39:55 +0100 (CET) Subject: Amber features 2026 In-Reply-To: <982EF2DB-F7C9-48CC-AD3F-EF5063535A97@oracle.com> References: <1C8344A8-B712-422D-9F66-FB4ED89373FC@oracle.com> <982EF2DB-F7C9-48CC-AD3F-EF5063535A97@oracle.com> Message-ID: <957379390.14745646.1768379995105.JavaMail.zimbra@univ-eiffel.fr> > From: "John Rose" > To: "Brian Goetz" , "Archie Cobbs" > > Cc: "Gavin Bierman" , "amber-dev" > > Sent: Wednesday, January 14, 2026 5:15:01 AM > Subject: Re: Amber features 2026 > On 13 Jan 2026, at 18:33, Brian Goetz wrote: >> While I totally understand why you would want to do that, I don't see the >> connection between pattern assignment and extending the type system to permit >> denotation of quantified or existential types? I don't see any patterns in your >> example, only type manipulation. >> What you're saying is that you'd like a conversion from Foo to `\exist T . >> Foo`. This is understandable, as wildcards are basically existentials >> already, and is just as safe as the the trick of calling an out-of-line generic >> method. >> But I just don't see the connection with pattern assignment? It seems like what >> you really want is "generic variables", to go along with generic methods and >> classes? > I?ve wanted this sort of thing from time to time. I think of the ask > as "local type variables", where the type variable is local to a block > (tighter control than local to method or class/interface). But it > would only be set via inference, not explicitly; in that it would > be a narrower feature than type variables on methods or classes. > The two other type variable occurrences (method, class) offer > explicit specification as well as inference. But there is no > occasion for explicit specification of a local type. If you > have a type you want to use explicitly, you just declare the > local with that type. > Other kinds of variables (fields, not locals) also do not benefit > from having their types inferred, for the same reason that the /var/ > keyword is only accepted on locals. (Inferring a type for var on > an API point is dangerously obscure, not worth the concision.) > So, local type vars. The form Archie mentions is also the one > that I have wondered about, these many years. > var x1a = foo(); // x1a has type inferred from foo() > T1 x1b = foo(); // so does x1b; now it is denotable as T1 > T1 x1c; // and now x1c has the same type too > { x1a = x1b; x1b = x1c; x1c = x1a; } // types are the same > Map x2 = bar(); // capturing g-type structure > T3 x3a = baz(); > List x3b = bat(); // checks result of baz is list of what x3a is > T4 x4; // ERROR; must have an initializer to drive inference > This might allow some new types to become denotable, so maybe > it?s dangerous. Maybe there is some useful sanitization move > that could apply to type variables captured this way, as with var. > But var definitely can capture non-denotables, despite sanitization. > var o1 = new Object() { int f; }; > o1.f++; // field WHOOZIT.f > o2a = new Object() { long f; static int Q; }; > T2 o2b = o2a; // rather odd > o2a.Q++; // static variable reference (deprecated syntax) > o2b.Q++; // again? > T2.Q++; // ERROR; unless T2 is a type alias instead of a type var > Oddly, the range of variation of such a type var is very narrow, > since it can be driven only from one use site, the initialization. > But it?s still a type var, if you squint, since the thing coming > out of the initializer expression can have type vars mixed into it. > Feature priority? Very low! It?s a "filling in the corners" move. > No known important use cases. The use case I had was avoiding > refactoring to a private generic method, because the body wanted > to access some local vars in an enclosing scope. In the end, > I think I just boxed the local vars in an array and moved on > with the generic helper method. It did make the code more > obscure, so having a local type var would have been an aid > in readability. But it?s rare to want to name that type, > and I can?t recall why I needed to. > In other words, I am not asking for a JEP or RFE for this. > Just laying out the case FTR, in case a use comes up later. > Maybe the balance shifts if/when we get reified generics, > since then there will be "more to capture". > There, got it all off my chest. Thanks Archie for fellow-traveling. > Now, back to 2026. For fields, i think I would prefer to have a way to denote the type of null and bottom/nothing. class A { List list = List.of(); // can be List list = List.of(); } Inside a method, you sometime need to access a static field (e.g. you can use it as a JIT "anchor") void main() { var o1 = new Object() { int f; static int Q; }; o1.Q++; // can be record T1() { static int Q; } // the compiler adds a package private constructor T1.Q++; // or enum T2 { static int Q; } // the compiler adds values()/valueOf() T2.Q++; // this does not compile // the keyword "final" is allowed but "static" is not static final class T3 { private T3() {} static int Q; } } another example is the class initializer idiom class DBFacade { public static DB getLazyDB() { final class DBInit { private DBInit() {} private static final DB INSTANCE = new DB(); } return DBInit.INSTANCE; } } Here the class DBInit is "static" because it is defined in a static context (inside the static method). So the two missing pieces are - being able to denote the type of null and/or nothing, - being able to declare a local class static * > ? John R?mi * also allow private classes in interface which is another hole to plug. -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Wed Jan 14 16:31:53 2026 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Wed, 14 Jan 2026 10:31:53 -0600 Subject: Amber features 2026 In-Reply-To: References: <1C8344A8-B712-422D-9F66-FB4ED89373FC@oracle.com> Message-ID: Hi Brian, On Tue, Jan 13, 2026 at 8:33?PM Brian Goetz wrote: > While I totally understand why you would want to do that, I don't see the > connection between pattern assignment and extending the type system to > permit denotation of quantified or existential types? > Well it's kind of a loose "connection" I guess :) I'm just pointing out that the two features have a common motivation: the ability to declare a variable that is initialized from some existing declared variable of an object. This is handy! This idea of "local type vars" has come up before and been rejected. That's fine, but if the underlying motivations are the same, then it seems like we are being inconsistent by promoting one feature while ignoring the other. They are both useful, and for the same reason (roughly speaking), so why not complete the picture while we're mucking with the language syntax? Admittedly, I'm asking not based on some conceptual language design principle, but simply because this particular omission has always bugged me and it seems relatively easy to fix without too much ugliness (maybe; to be determined). -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From duke at openjdk.org Mon Jan 19 22:10:49 2026 From: duke at openjdk.org (Nicolai Parlog) Date: Mon, 19 Jan 2026 22:10:49 GMT Subject: [amber-docs] RFR: Capitalize article titles according to Chicago style Message-ID: Capitalize article titles according to Chicago style ------------- Commit messages: - Capitalize article titles according to Chicago style Changes: https://git.openjdk.org/amber-docs/pull/28/files Webrev: https://webrevs.openjdk.org/?repo=amber-docs&pr=28&range=00 Stats: 2 lines in 2 files changed: 0 ins; 0 del; 2 mod Patch: https://git.openjdk.org/amber-docs/pull/28.diff Fetch: git fetch https://git.openjdk.org/amber-docs.git pull/28/head:pull/28 PR: https://git.openjdk.org/amber-docs/pull/28 From briangoetz at openjdk.org Mon Jan 19 22:10:50 2026 From: briangoetz at openjdk.org (Brian Goetz) Date: Mon, 19 Jan 2026 22:10:50 GMT Subject: [amber-docs] RFR: Capitalize article titles according to Chicago style In-Reply-To: References: Message-ID: On Sun, 18 Jan 2026 21:24:19 GMT, Nicolai Parlog wrote: > Capitalize article titles according to Chicago style Marked as reviewed by briangoetz (Lead). ------------- PR Review: https://git.openjdk.org/amber-docs/pull/28#pullrequestreview-3675781159 From briangoetz at openjdk.org Mon Jan 19 22:11:58 2026 From: briangoetz at openjdk.org (Brian Goetz) Date: Mon, 19 Jan 2026 22:11:58 GMT Subject: [amber-docs] RFR: Add "Data-Oriented Programming for Java: Beyond Records" In-Reply-To: References: Message-ID: On Sun, 18 Jan 2026 21:25:00 GMT, Nicolai Parlog wrote: > Add "Data-Oriented Programming for Java: Beyond Records" Marked as reviewed by briangoetz (Lead). ------------- PR Review: https://git.openjdk.org/amber-docs/pull/29#pullrequestreview-3675781465 From duke at openjdk.org Mon Jan 19 22:11:58 2026 From: duke at openjdk.org (Nicolai Parlog) Date: Mon, 19 Jan 2026 22:11:58 GMT Subject: [amber-docs] RFR: Add "Data-Oriented Programming for Java: Beyond Records" Message-ID: Add "Data-Oriented Programming for Java: Beyond Records" ------------- Commit messages: - Add "Data-Oriented Programming for Java: Beyond Records" Changes: https://git.openjdk.org/amber-docs/pull/29/files Webrev: https://webrevs.openjdk.org/?repo=amber-docs&pr=29&range=00 Stats: 689 lines in 2 files changed: 689 ins; 0 del; 0 mod Patch: https://git.openjdk.org/amber-docs/pull/29.diff Fetch: git fetch https://git.openjdk.org/amber-docs.git pull/29/head:pull/29 PR: https://git.openjdk.org/amber-docs/pull/29 From nlisker at openjdk.org Mon Jan 19 22:37:19 2026 From: nlisker at openjdk.org (Nir Lisker) Date: Mon, 19 Jan 2026 22:37:19 GMT Subject: [amber-docs] RFR: Add "Data-Oriented Programming for Java: Beyond Records" In-Reply-To: References: Message-ID: On Sun, 18 Jan 2026 21:25:00 GMT, Nicolai Parlog wrote: > Add "Data-Oriented Programming for Java: Beyond Records" site/design-notes/beyond-records.md line 117: > 115: This is more concise, less error-prone, and easier to read: > 116: > 117: ```{.java} I don't see this text block rendered with Java syntax highlights. I usually use just the language name without `{. }`. ------------- PR Review Comment: https://git.openjdk.org/amber-docs/pull/29#discussion_r2706234767