On 08/11/2025 20:08, Rob Landers wrote:
The moment we allow "namespace prefixes", we introduce questions that need to be fleshed out separately and with care. Do we treat "Acme\AuthLib\Session" and "Acme\AuthLib\Services" as related? Even if they come from different vendors and are unrelated in any way? Are namespaces hierarchical or just flat strings that happen to contain separators?


While I appreciate the desire to keep things simple, I don't think we can avoid asking those questions, we can only propose answers. In your current RFC, the answers are:

- No two namespaces are related, even if their names imply a hierarchy.
- Two "internal" classes in the same namespace can see each other even if they are written by different vendors.


Today namespaces are a name resolution mechanism, not a semantic hierarchy. Matching by prefix would start treating them as a package system, and I explicitly am trying to avoid that in this RFC.

I don't think that's true. The language already recognises the namespace separator, and that if you are in namespace "Acme\AuthLib", an unqualified reference to "Services\SessionManager" refers to "Acme\AuthLib\Services\SessionManager". That doesn't require any concept of "package", but it is clearly based on the conception of namespaces as a hierarchy.


By restricting the rule to exact namespace equality, the feature is straightforward to explain and to understand. It also prevents "accidental" access because two unrelated namespaces happen to share a prefix.

My concern is that by restricting it so much, we would prevent most of the real-world use cases for it, since the reality is that people use much more complex namespace hierarchies.


If you have a concrete, unambiguous rule for prefix-based access that wouldn’t cause surprises or make assumptions about how people organise their codebases, I’d be happy to discuss it. Right now, every version I’ve explored would reopen the "module"/"package" debate from this summer.

I mentioned, briefly, two possibilities:

I think we need a keyword or attribute which takes as a parameter either the namespace prefix, or the number of levels to match

To spell those out, the prefix version could look like this:

namespace Acme\AuthLib\Somewhere\Deep\In\Package;
// ...
#[NamespacePrivate('Acme\AuthLib', includeChildren: true)]


A number of levels version could look like this:

namespace Acme\AuthLib\Somewhere\Deep\In\Package;
// ...
#[NamespacePrivate(minLevels: 2, maxLevels: null)]

There's all sorts of variations on how those arguments could be presented, keywords vs attributes, etc; but the key point is the language is not defining where the boundary is, it is requiring the user to do so.


The prefix-based approach could be expanded into an allow-list that didn't require any relationship to the current namespace at all:

 namespace Acme\AuthLib\Somewhere\Deep\In\Package;
// ...
#[AllowNamespace('Acme\AuthLib\*')]
#[AllowNamespace('Zeppo\FrameworkCore\*')]

Or even an allow-deny rule system:

#[AllowNamespace('Acme\AuthLib\*')]
#[DenyNamespace('Acme\AuthLib\Plugins\*')]

At that point, it's admittedly rather complex, but it makes *even fewer* assumptions about what constitutes a "package".


--
Rowan Tommins
[IMSoP]

Reply via email to