<!DOCTYPE html><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<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 class="moz-cite-prefix">On 2/13/2026 8:11 AM, Øyvind Kvien
wrote:<br>
</div>
<blockquote type="cite" cite="mid:CAKipqtKa+7R_O8K7XQv5NCEe2bkfox0X32hgjR0f-dc3yW8NTQ@mail.gmail.com">
<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 class="gmail-overflow-visible! gmail-px-0!"><div class="gmail-contain-inline-size gmail-rounded-2xl gmail-corner-superellipse/1.1 gmail-relative gmail-bg-token-sidebar-surface-primary"><div class="gmail-overflow-y-auto gmail-p-4" dir="ltr"><code class="gmail-whitespace-pre!"><span class="gmail-hljs-keyword">public</span> <span class="gmail-hljs-keyword">final</span> <span class="gmail-hljs-keyword">class</span> <span class="gmail-hljs-title gmail-class_">Patient</span> {
<span class="gmail-hljs-keyword">private</span> <span class="gmail-hljs-title gmail-function_">Patient</span><span class="gmail-hljs-params">()</span> {}
<span class="gmail-hljs-keyword">public</span> <span class="gmail-hljs-keyword">static</span> <span class="gmail-hljs-keyword">final</span> <span class="gmail-hljs-type">String</span> <span class="gmail-hljs-variable">PATIENT_REFERENCE_PREFIX</span> <span class="gmail-hljs-operator">=</span> <span class="gmail-hljs-string">"Patient/"</span>;
<span class="gmail-hljs-keyword">public</span> <span class="gmail-hljs-keyword">static</span> <span class="gmail-hljs-keyword">final</span> <span class="gmail-hljs-type">Pattern</span> <span class="gmail-hljs-variable">PATIENT_IDENTIFIER_PATTERN</span> <span class="gmail-hljs-operator">=</span>
Pattern.compile(<span class="gmail-hljs-string">"^Patient/(.*)"</span>, Pattern.CASE_INSENSITIVE);
<span class="gmail-hljs-keyword">public</span> <span class="gmail-hljs-keyword">record</span> <span class="gmail-hljs-title gmail-class_">PatientIdentifier</span><span class="gmail-hljs-params">(String id)</span> {}
<span class="gmail-hljs-keyword">public</span> <span class="gmail-hljs-keyword">static</span> PatientIdentifier <span class="gmail-hljs-title gmail-function_">getPatientIdentifier</span><span class="gmail-hljs-params">(<span class="gmail-hljs-meta">@Nullable</span></span> Reference patientRef) {
<span class="gmail-hljs-keyword">if</span> (patientRef == <span class="gmail-hljs-literal">null</span> || patientRef.getReference() == <span class="gmail-hljs-literal">null</span>)
<span class="gmail-hljs-keyword">return</span> <span class="gmail-hljs-keyword">new</span> <span class="gmail-hljs-title gmail-class_">PatientIdentifier</span>(Str.EMPTY);
<span class="gmail-hljs-type">var</span> <span class="gmail-hljs-variable">matcher</span> <span class="gmail-hljs-operator">=</span> PATIENT_IDENTIFIER_PATTERN.matcher(patientRef.getReference());
<span class="gmail-hljs-keyword">return</span> <span class="gmail-hljs-keyword">new</span> <span class="gmail-hljs-title gmail-class_">PatientIdentifier</span>(matcher.find() ? matcher.group(<span class="gmail-hljs-number">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 class="gmail-overflow-visible! gmail-px-0!"><div class="gmail-contain-inline-size gmail-rounded-2xl gmail-corner-superellipse/1.1 gmail-relative gmail-bg-token-sidebar-surface-primary"><div class="gmail-overflow-y-auto gmail-p-4" dir="ltr"><code class="gmail-whitespace-pre!"><span class="gmail-hljs-keyword">public</span> <span class="gmail-hljs-keyword">interface</span> <span class="gmail-hljs-title gmail-class_">Patient</span> {
<span class="gmail-hljs-title gmail-class_">String</span> <span class="gmail-hljs-variable gmail-constant_">PATIENT_REFERENCE_PREFIX</span> = <span class="gmail-hljs-string">"Patient/"</span>;
record <span class="gmail-hljs-title gmail-class_">PatientIdentifier</span>(<span class="gmail-hljs-title gmail-class_">String</span> id) {}
<span class="gmail-hljs-keyword">static</span> <span class="gmail-hljs-title gmail-class_">PatientIdentifier</span> <span class="gmail-hljs-title gmail-function_">getPatientIdentifier</span>(<span class="gmail-hljs-params">...</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 class="gmail-overflow-visible! gmail-px-0!"><div class="gmail-contain-inline-size gmail-rounded-2xl gmail-corner-superellipse/1.1 gmail-relative gmail-bg-token-sidebar-surface-primary"><div class="gmail-overflow-y-auto gmail-p-4" dir="ltr"><code class="gmail-whitespace-pre!"><span class="gmail-hljs-keyword">public</span> <span class="gmail-hljs-keyword">namespace</span> <span class="gmail-hljs-title gmail-class_">Patient</span> {
<span class="gmail-hljs-title gmail-class_">String</span> <span class="gmail-hljs-variable gmail-constant_">PATIENT_REFERENCE_PREFIX</span> = <span class="gmail-hljs-string">"Patient/"</span>;
<span class="gmail-hljs-title gmail-class_">Pattern</span> <span class="gmail-hljs-variable gmail-constant_">PATIENT_IDENTIFIER_PATTERN</span> =
<span class="gmail-hljs-title gmail-class_">Pattern</span>.<span class="gmail-hljs-title gmail-function_">compile</span>(<span class="gmail-hljs-string">"^Patient/(.*)"</span>, <span class="gmail-hljs-title gmail-class_">Pattern</span>.<span class="gmail-hljs-property">CASE_INSENSITIVE</span>);
record <span class="gmail-hljs-title gmail-class_">PatientIdentifier</span>(<span class="gmail-hljs-title gmail-class_">String</span> id) {}
<span class="gmail-hljs-title gmail-class_">PatientIdentifier</span> <span class="gmail-hljs-title gmail-function_">getPatientIdentifier</span>(<span class="gmail-hljs-params"><span class="gmail-hljs-meta">@Nullable</span></span> <span class="gmail-hljs-title gmail-class_">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>
</body>
</html>