On 30 May 2025, at 21:29, Rowan Tommins [IMSoP] <[email protected]> wrote:
>
> On 30 May 2025 19:21:08 BST, Alwin Garside <[email protected]> wrote:
>> In the example above, I image calling or extending the Foo::bar()
method from
>> somewhere outside the Acme
namespace would trigger an E_USER_WARNING or E_USER_NOTICE.
>> The warning/notice could then be suppressed when explicitly overriding an #[\Internal]
>> method with #[\Override]
.
>
>
> I don't see any reason for the message to be any quieter or easier to override than
> calling a private method.
If there were a dedicated internal
modifier keyword, sure. However if one simply wants
to advertise clearly to other developers that they should expect the code to break anytime using an
attribute, I feel a compile-time critical error is a bit too strict.
>
> Indeed, one use of an internal/module-private feature would be when the author wants to split
> up a class that has a large number of private methods: the new classes need to be able to talk to
> each other, so the existing "private" keyword is no longer appropriate, but the intended
> surface to users of the library has not changed. The user is making exactly the same decision by
> ignoring the "internal" flag as they are if they use reflection or code-rewriting to
> ignore/remove the "private" flag.
I understand your point, but playing devil's advocate for a minute here: I'd argue that if
a class reaches the point where it has too many private methods, something has clearly gone wrong in
the architecture or abstraction of that class. It probably means part of the functionality needs to
be hoisted out to a separate class with its own self-contained, stable interface.
One could also argue that if the author really wishes to break private methods up across multiple
classes, they could also use reflection (or preferably: a method call wrapped in a closure bound to
the target class) to access their own private methods.
My experience with module-level visibility out in the wild (mostly in Java), has mostly been
libraries where the authors apparently couldn't be bothered to dedicate to a stable interface
for more specific implementations of certain template-pattern adapters and the like – the Android
source code is full of this.
[rant]
I specifically remember dealing with a DB adapter interface and accompanying abstract class, along
with implementations for several DBMSs. There was an implementation for the specific DBMS I wanted
to use, however, per the interface, it was completely tied into a separate pagination construction
which led to a leaky abstraction, and was badly optimized for my use case. I just needed to override
one or two methods to make it work for me, but the platform visibility on those methods meant I had
to copy-paste both the abstract class and the adapter class to fix the functionality, giving me more
code to maintain in the process.
I think this is a good example where package/module-level visibility makes developers complacent,
and not care about offering a library that is easy to extend or encapsulate.
[/rant]
Alwin