<head><!-- BaNnErBlUrFlE-HeAdEr-start -->
<style>
#pfptBannerjasy359 { all: revert !important; display: block !important;
visibility: visible !important; opacity: 1 !important;
background-color: #60beeb !important;
max-width: none !important; max-height: none !important }
.pfptPrimaryButtonjasy359:hover, .pfptPrimaryButtonjasy359:focus {
background-color: #77a8c4 !important; }
.pfptPrimaryButtonjasy359:active {
background-color: #8193a0 !important; }
html:root, html:root>body { all: revert !important; display: block !important;
visibility: visible !important; opacity: 1 !important; }
</style>
<!-- BaNnErBlUrFlE-HeAdEr-end -->
</head><!-- BaNnErBlUrFlE-BoDy-start -->
<!-- Preheader Text : BEGIN -->
<div style="display:none !important;display:none;visibility:hidden;mso-hide:all;font-size:1px;color:#ffffff;line-height:1px;max-height:0px;opacity:0;overflow:hidden;">
Thank you for the thoughtful response. I agree that removing a private constructor and a few static modifiers alone would not justify introducing a new top-level construct. If this were purely about shaving off ceremony, I agree that it would</div>
<!-- Preheader Text : END -->
<!-- Email Banner : BEGIN -->
<div style="display:none !important;display:none;visibility:hidden;mso-hide:all;font-size:1px;color:#ffffff;line-height:1px;max-height:0px;opacity:0;overflow:hidden;">ZjQcmQRYFpfptBannerStart</div>
<!--[if ((ie)|(mso))]>
<table border="0" cellspacing="0" cellpadding="0" width="100%" style="padding: 0px 0px 10px 0px; direction: ltr" lang="en"><tr><td>
<table border="0" cellspacing="0" cellpadding="0" style="padding: 0px 8px 6px 8px; width: 100%; border-radius:4px; border-top:4px solid #8193a0;background-color:#60beeb;"><tr><td valign="top">
<table align="left" border="0" cellspacing="0" cellpadding="0" style="padding: 0px 8px 4px 8px; font-size: 12px; line-height: 16px">
<tr><td style="color:#000000; font-family: 'Arial', sans-serif; font-weight:bold; font-size:14px; line-height: 20px; direction: ltr">
This Message Is From an Untrusted Sender
</td></tr>
<tr><td style="color:#000000; font-weight:normal; font-family: 'Arial', sans-serif; font-size:12px; direction: ltr">
You have not previously corresponded with this sender.
</td></tr>
</table>
<![if ie]><br clear="all"><![endif]>
<table align="right" border="0" cellspacing="0" cellpadding="0" style="padding: 0px 0px 4px 0px; font-size: 14px; line-height: 36px"><tr>
<td style="direction: ltr"> <a target="_blank" href="https://us-phishalarm-ewt.proofpoint.com/EWT/v1/ACWV5N9M2RV99hQ!Op20OCZl8mBmmhMrd1k0lUr66H9rycR5s__cRVcFCNggENwSP-8pAB__PHFaIJ3zkle1oA92r_-R-Yw3YsXFVhqeuwimVck8CDSvpc3CicHYJhdo9Th8_8Z8U24c5yM$" style="mso-padding-alt: 7px; padding: 7px; border-radius: 2px; border: 1px solid #666666; "><strong style="font-weight: normal; color: #000000; text-decoration: none; font-family: 'Arial', sans-serif; font-size: 14px;"> Report Suspicious </strong></a> </td>
</tr></table>
</td></tr></table>
</td></tr></table>
<![endif]-->
<![if !((ie)|(mso))]>
<div dir="ltr" lang="en" id="pfptBannerjasy359" style="all: revert !important; display:block !important; text-align: left !important; margin: 0 0 10px 0 !important; padding:7px 16px 8px 16px !important; border-radius: 4px !important; min-width: 200px !important; background-color: #60beeb !important; background-color: #60beeb; border-top: 4px solid #8193a0 !important; border-top: 4px solid #8193a0;">
<div id="pfptBannerjasy359" style="all: unset !important; float:left !important; display:block !important; margin: 1px 0 1px 0 !important; max-width: 600px !important;">
<div id="pfptBannerjasy359" style="all: unset !important; display:block !important; visibility: visible !important; background-color: #60beeb !important; color:#000000 !important; color:#000000; font-family: 'Arial', sans-serif !important; font-family: 'Arial', sans-serif; font-weight:bold !important; font-weight:bold; font-size:14px !important; line-height:1.29 !important; line-height:1.29">
This Message Is From an Untrusted Sender
</div>
<div id="pfptBannerjasy359" style="all: unset !important; display:block !important; visibility: visible !important; background-color: #60beeb !important; color:#000000 !important; color:#000000; font-weight:normal; font-family: 'Arial', sans-serif !important; font-family: 'Arial', sans-serif; font-size:12px !important; line-height:1.5 !important; line-height:1.5; margin-top:2px !important;">
You have not previously corresponded with this sender.
</div>
</div>
<div id="pfptBannerjasy359" style="all: unset !important; float: right !important; display: block !important; display: block; margin-left: 16px !important; margin-top: 1px !important; text-align: right !important; width: fit-content !important; font-size: 12px !important">
<a id="pfptBannerjasy359" href="https://us-phishalarm-ewt.proofpoint.com/EWT/v1/ACWV5N9M2RV99hQ!Op20OCZl8mBmmhMrd1k0lUr66H9rycR5s__cRVcFCNggENwSP-8pAB__PHFaIJ3zkle1oA92r_-R-Yw3YsXFVhqeuwimVck8CDSvpc3CicHYJhdo9Th8_8Z8U24c5yM$"
style="all: unset !important; display: inline-block !important; text-decoration: none">
<div class="pfptPrimaryButtonjasy359" style="display: inline-block !important; display: inline-block; visibility: visible !important; opacity: 1 !important; color: #000000 !important; color: #000000; font-family: 'Arial', sans-serif !important; font-family: 'Arial', sans-serif; font-size: 14px !important; font-weight: normal !important; text-decoration: none !important; border-radius: 2px !important; margin-top: 3px !important; margin-bottom: 3px !important; margin-left: 16px !important; padding: 7.5px 16px !important; white-space: nowrap !important; width: fit-content !important;
border: 1px solid #666666">
Report Suspicious
</div>
</a>
</div>
<div style="clear: both !important; display: block !important; visibility: hidden !important; line-height: 0 !important; font-size: 0.01px !important; height: 0px"> </div>
</div>
<![endif]>
<div style="display:none !important;display:none;visibility:hidden;mso-hide:all;font-size:1px;color:#ffffff;line-height:1px;max-height:0px;opacity:0;overflow:hidden;">ZjQcmQRYFpfptBannerEnd</div>
<!-- Email Banner : END -->
<!-- BaNnErBlUrFlE-BoDy-end -->
<div dir="ltr">Thank you for the thoughtful response.<br><br>I agree that removing a private constructor and a few static modifiers alone would not justify introducing a new top-level construct. If this were purely about shaving off ceremony, I agree that it would not meet the bar.<br><br>The distinction I am trying to surface is slightly different. It is less about boilerplate and more about the semantic intent of grouping vs. the semantic intent of identity.<br><br>A class—and similarly a declared singleton—introduces a type with identity, a lifecycle, and the conceptual possibility of state. Even a "utility class" is technically a type that can be used in reflection, as a generic bounds carrier, or as a synchronization lock.<br><br>By contrast, a namespace construct would model pure structural grouping. It would allow us to group related functions and constants without also introducing the semantics of a type. In this sense, it decouples the organization of code from the object model.<br><br>I appreciate the Scala-style object direction. It is a powerful way to reify statics into the instance world. However, an object still introduces an entity with instance semantics. If I have a collection of pure, stateless mathematical functions, elevating them to an "instance" (a singleton) introduces object-model semantics that are not conceptually required for simple structural grouping.<br><br>The deeper question for Java might be: Must every grouping of code be a type?<br><br>If the answer is yes, then the Scala-style object is indeed the superior evolution. But if there is value in a "type-less" container that exists purely for structural organization, name resolution, and the developer's mental model, then a namespace offers a path that doesn't just "double down" on statics, but moves them into a more appropriate, restricted context.<br></div><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Wed, Feb 25, 2026 at 6:47 PM Brian Goetz <<a href="mailto:brian.goetz@oracle.com">brian.goetz@oracle.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><u></u>
<div>
<font size="4" face="monospace">The frictions you outline here are
real. What's less clear is whether they are a big enough deal to
be worth adding new top-level concepts to the language; I think
most developers are willing to shrug this off and say "yeah, I
have to use classes to simulate namepaces, and that means I have
to engage in one or two bits of ceremony, but ... fine, I'll do
that and get on with my life." Which is an entirely pragmatic
viewpoint; the extra boilerplate of an inaccessible constructor,
and the sprinkling of `static`, is a relatively small bit of
ceremony. <br>
<br>
What I find uncompelling about this proposal is that it is
_purely_ about the "code golf" of eliminating this bit of
boilerplate, mostly doubling down on one of the weakest parts of
the language -- static members. It doesn't offer us any new way
to abstract over anything, it just removes some boilerplate from
the "bag of static members" classes. <br>
<br>
If I felt these were a bigger deal, though, there is a _much_
better solution in evidence for these problems and more: something
like Scala's `object` declaration. This achieves the boilerplate
goals through solving some real semantic problems: lifecycle
management of singletons, plus elevating static behavior to
instance behavior. (This strengthens statics rather than just
doubling down on them.)<br>
<br>
(Notably, though, even though this solution is better in pretty
much every way, and significantly better in some ways, I'm still
not sure whether it meets the bar for being worth working on.)<br>
<br>
For those who are unfamiliar: you can declare a singleton object
much like you do a class:<br>
<br>
object Patient { // could implement interfaces here <br>
public final String PATIENT_REFERENCE_PREFIX = "Patient/";<br>
public final Pattern PATIENT_IDENTIFIER_PATTERN =
Pattern.compile(...);<br>
// methods too<br>
}<br>
<br>
Here, the name `Patient` is bound to the singleton _instance_, so
you use the same use-site syntax:<br>
<br>
String s = Patient.PATIENT_REFERENCE_PREFIX + ...<br>
<br>
but instead of this being intepreted as
<class>.<static-member>, it is interpreted as
<instance>.<instance-member>. So they look like
static members, but we can abstract over them through interfaces:<br>
<br>
object FooBehaviors implements Comparator<Foo> { <br>
int compare(Foo a, Foo b) { ... }<br>
}<br>
<br>
...<br>
<br>
foos.sort(FooBehaviors);<br>
<br>
(Perhaps a more familiar spelling for "object" here might be
"singleton".)<br>
<br>
So:<br>
<br>
- Not sure the problem is worth solving<br>
- If it is worth solving, declared singletons dominate namespaces
by a lot<br>
- Even with the much bigger payback of declared singletons, still
not sure its worth solving<br>
<br>
<br>
</font><br>
<div>On 2/13/2026 8:11 AM, Øyvind Kvien
wrote:<br>
</div>
<blockquote type="cite">
<div dir="ltr">
<p>Dear Amber team,</p>
<p>I would like to explore the idea of introducing a first-class
namespace construct in Java, intended to support data-oriented
and functional programming styles without repurposing classes
or interfaces as containers for static members.</p>
<p>Motivation</p>
<p>In data-oriented and mostly functional Java codebases, it is
common to group:</p>
<ul>
<li>
<p>Stateless utility functions</p>
</li>
<li>
<p>Related constants</p>
</li>
<li>
<p>Small domain records</p>
</li>
<li>
<p>Parsing and validation logic</p>
</li>
</ul>
<p>Today, the idiomatic way to express this grouping is:</p>
<pre><div><div dir="ltr"><code><span>public</span> <span>final</span> <span>class</span> <span>Patient</span> {
<span>private</span> <span>Patient</span><span>()</span> {}
<span>public</span> <span>static</span> <span>final</span> <span>String</span> <span>PATIENT_REFERENCE_PREFIX</span> <span>=</span> <span>"Patient/"</span>;
<span>public</span> <span>static</span> <span>final</span> <span>Pattern</span> <span>PATIENT_IDENTIFIER_PATTERN</span> <span>=</span>
Pattern.compile(<span>"^Patient/(.*)"</span>, Pattern.CASE_INSENSITIVE);
<span>public</span> <span>record</span> <span>PatientIdentifier</span><span>(String id)</span> {}
<span>public</span> <span>static</span> PatientIdentifier <span>getPatientIdentifier</span><span>(<span>@Nullable</span></span> Reference patientRef) {
<span>if</span> (patientRef == <span>null</span> || patientRef.getReference() == <span>null</span>)
<span>return</span> <span>new</span> <span>PatientIdentifier</span>(Str.EMPTY);
<span>var</span> <span>matcher</span> <span>=</span> PATIENT_IDENTIFIER_PATTERN.matcher(patientRef.getReference());
<span>return</span> <span>new</span> <span>PatientIdentifier</span>(matcher.find() ? matcher.group(<span>1</span>) : Str.EMPTY);
}
}
</code></div></div></pre>
<p>This works, but it introduces conceptual and syntactic
friction:</p>
<ul>
<li>
<p>The type is not meant to be instantiated.</p>
</li>
<li>
<p>The constructor must be manually suppressed.</p>
</li>
<li>
<p>Everything must be explicitly marked static.</p>
</li>
<li>
<p>The type is not modeling an object or abstraction; it is
modeling a namespace.</p>
</li>
</ul>
<p>In practice, such classes act as packages within packages.</p>
<p>An alternative is to use an interface as a namespace:</p>
<pre><div><div dir="ltr"><code><span>public</span> <span>interface</span> <span>Patient</span> {
<span>String</span> <span>PATIENT_REFERENCE_PREFIX</span> = <span>"Patient/"</span>;
record <span>PatientIdentifier</span>(<span>String</span> id) {}
<span>static</span> <span>PatientIdentifier</span> <span>getPatientIdentifier</span>(<span>...</span>) { ... }
}
</code></div></div></pre>
<p>However, interfaces are primarily intended to model
polymorphic contracts and substitution. Repurposing them as
namespace containers can blur intent and introduce conceptual
confusion. The well-known “constant interface” anti-pattern
illustrates this discomfort.</p>
<p>In short, Java lacks a first-class way to express “this is a
namespace for related functions and data types.”</p>
<p>Design Goal</p>
<p>Provide a language-level construct that:</p>
<ul>
<li>
<p>Represents a pure namespace (not a type with identity).</p>
</li>
<li>
<p>Cannot be instantiated or extended.</p>
</li>
<li>
<p>Groups related functions, constants, and nested types.</p>
</li>
<li>
<p>Supports access modifiers.</p>
</li>
<li>
<p>Avoids boilerplate such as private constructors and
repeated static.</p>
</li>
<li>
<p>Preserves Java’s explicitness and readability.</p>
</li>
</ul>
<p>Strawman Syntax</p>
<p>One possible direction:</p>
<pre><div><div dir="ltr"><code><span>public</span> <span>namespace</span> <span>Patient</span> {
<span>String</span> <span>PATIENT_REFERENCE_PREFIX</span> = <span>"Patient/"</span>;
<span>Pattern</span> <span>PATIENT_IDENTIFIER_PATTERN</span> =
<span>Pattern</span>.<span>compile</span>(<span>"^Patient/(.*)"</span>, <span>Pattern</span>.<span>CASE_INSENSITIVE</span>);
record <span>PatientIdentifier</span>(<span>String</span> id) {}
<span>PatientIdentifier</span> <span>getPatientIdentifier</span>(<span><span>@Nullable</span></span> <span>Reference</span> patientRef) {
...
}
}
</code></div></div></pre>
<p>Semantics (strawman)</p>
<ul>
<li>
<p>namespace introduces a named scope at top level.</p>
</li>
<li>
<p>Members are implicitly static.</p>
</li>
<li>
<p>Fields are implicitly static final unless specified
otherwise.</p>
</li>
<li>
<p>Nested types are implicitly static.</p>
</li>
<li>
<p>The namespace itself:</p>
<ul>
<li>
<p>Cannot be instantiated.</p>
</li>
<li>
<p>Cannot implement or extend anything.</p>
</li>
<li>
<p>Cannot declare instance state.</p>
</li>
</ul>
</li>
<li>
<p>Initialization semantics follow class static
initialization rules.</p>
</li>
<li>
<p>At the bytecode level, the namespace may be compiled to a
synthetic final class, preserving JVM compatibility.</p>
</li>
</ul>
<p>Why Not Just Use Classes?</p>
<p>Using final classes with private constructors is serviceable
but semantically misleading:</p>
<ul>
<li>
<p>A class suggests instantiability, inheritance
relationships, or type abstraction.</p>
</li>
<li>
<p>Namespace-only classes are often flagged as utility
classes.</p>
</li>
<li>
<p>The pattern is common enough that it arguably deserves
first-class support.</p>
</li>
</ul>
<p>Why Not Just Use Interfaces?</p>
<p>Interfaces are designed primarily for polymorphic
abstraction. Using them as namespace containers:</p>
<ul>
<li>
<p>Conflates two distinct concepts (contract vs grouping).</p>
</li>
<li>
<p>Introduces ambiguity in API design intent.</p>
</li>
<li>
<p>Encourages patterns that may confuse less experienced
developers.</p>
</li>
</ul>
<p>Providing a dedicated construct allows interfaces to remain
focused on substitution and abstraction.</p>
<p>Interaction With Existing Features</p>
<p>Questions for exploration include:</p>
<ul>
<li>
<p>Should namespace members require explicit static, or be
implicitly static?</p>
</li>
<li>
<p>Should access modifiers default to the namespace’s
modifier?</p>
</li>
<li>
<p>How do annotations apply to the namespace?</p>
</li>
<li>
<p>Should nested namespaces be allowed?</p>
</li>
<li>
<p>How does reflection expose namespaces?</p>
</li>
<li>
<p>How should Javadoc render them?</p>
</li>
</ul>
<p>A minimal version could require explicit modifiers and treat
namespaces as a restricted form of top-level type compiled to
a synthetic final class.</p>
<p>Summary</p>
<p>As Java evolves toward stronger support for data-oriented
programming (records, pattern matching, etc.), it may be worth
revisiting how we express stateless domain logic and function
groupings.</p>
<p>A first-class namespace construct could:</p>
<ul>
<li>
<p>Reduce boilerplate.</p>
</li>
<li>
<p>Clarify intent.</p>
</li>
<li>
<p>Preserve the role of classes and interfaces.</p>
</li>
<li>
<p>Improve expressiveness for functional-style Java.</p>
</li>
</ul>
<p>I would be interested in feedback on:</p>
<ol>
<li>
<p>Whether this problem is considered significant enough.</p>
</li>
<li>
<p>Whether a namespace construct fits Java’s philosophy.</p>
</li>
<li>
<p>Whether there are smaller or more incremental ways to
address the issue.</p>
</li>
</ol>
<p>Best regards,<br>
Øyvind Kvien</p>
<p><br>
</p>
</div>
</blockquote>
<br>
</div>
</blockquote></div>