<!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>