On Mon, May 11, 2026, at 10:33 AM, Rob Landers wrote:
> On Mon, May 11, 2026, at 16:58, Daniel Scherzer wrote:

>> Surprisingly I think adding an entirely new syntax would actually result in 
>> the fewest breaking changes when userland classes add friends, because there 
>> is no ambiguity. `$u->id` always refers to the `id` on whatever class `$u` 
>> happens to be, including applying any shadowing; if you want to be sure to 
>> access the base `User::$id`, use `<$u as User>->id`.
>> 
>> Before I dive in and actually add that, what do people think?
>
> By the end of it, I basically arrived at a calculus that makes a sorta 
> sense. Visibility levels are sets of callers, partial-ordered by 
> inclusion. An override is admissible iff the child's caller set is a 
> superset of the parent's at the call site. P's caller set for `$x` with 
> `friend F` is {P, F}; C's shadowing with `protected $x` gives {C ∪ 
> descendants(C)}; incomparable, so the override violates LSP.
>
> Through that lens, we can look at your options you identified.
>
> Option 1 basically kills the entire feature.
>
> Option 3 breaks polymorphism. It throws away legitimate overrides.
>
> Option 4 is an escape hatch, not a solution. There's already RFCs for 
> "as" in-progress, so you'd step on some toes there. Heh, I think I have 
> even proposed "as" before and ... from experience, competing with 
> someone's in-progress RFC without discussion with them beforehand is a 
> great way to have people get mad at you on this list.
>
> Option 2 is probably the closest "right" answer. It prevents there from 
> being invalid caller sets and can provide meaningful error messages at 
> compile time: "name collides with friended private variable; must 
> friend with class F or change the name x".
>
> Another option to consider is not allowing private variables/methods to 
> be accessed by friends. Only protected variables/methods. This allows 
> inheritance to work as normal and guarantees overrides are compatible.
>
> — Rob

Honestly, this seems like the easiest model to explain to people.  A friend 
class has the same access as a child class, ie, it gets protected but not 
private access.  That's a very simple rule to document and explain, and seems 
like it would side-step a number of issues.  (We had a similar conversation for 
aviz, IIRC, which is how we ended up on private => final and readonly => 
protected(set) simplifying a lot of issues.)

That said, I am still skeptical.  This seems simple enough, but I worry that 
it's still attacking the general problem in too specific a way (compared to 
modules or similar).

--Larry Garfield

Reply via email to