On Sun, May 28, 2023, at 6:52 AM, David Gebler wrote:
> On Sun, May 28, 2023 at 10:33 AM Rowan Tommins <rowan.coll...@gmail.com>
> wrote:
>
>> I don't follow. If a property is public, then code outside the class can
>> rely on being able to access it. That seems to me to be a contract between
>> the class and its users, not an implementation detail - e.g. removing the
>> property, or changing its type, would be a compatibility break. A property
>> can also be inherited from a base class, at which point there is a contract
>> that all descendants of that base class will have the property available.
>> So it seems logical that that contract could also be included in an
>> interface.
>>
>>
> That's why you can declare constants in an interface (a static final
> property, to use the lexicon of Java) which we can already do in PHP. At
> the point you want to bring mutable state into an interface, it's a design
> smell that what you want, really, is an abstract class or perhaps
> composition.

Almost never is an abstract class what you want, frankly.  An abstract class 
unnecessarily conflates "is a special case of" and "reuses code from" into a 
single syntax.  "Making one thing do two things" is a design flaw in most of 
computer science, and one that PHP has been bitten by multiple times.

cf: https://www.garfieldtech.com/blog/beyond-abstract

> A couple of languages do allow mutable properties on interfaces, TypeScript
> being one of them, so yes it's not an unheard of feature - but in TS/JS
> it's a lot more idiomatic to directly access properties than it is in PHP.
> I'm not too familiar with C# personally but I have a vague recall that the
> idea of properties on interfaces there is more akin to the property hooks
> RFC than Nick's proposal here. And although I'm a little uncomfortable with
> encouraging getters and setters on interfaces, I'm fully behind property
> hooks, I hope that RFC passes.
>
> PHP already has the sufficient design tools to follow SOLID principles and
> established design patterns well. If this RFC was in the language tomorrow,
> you wouldn't be able to do anything you can't already do and do more
> safely, more robustly, with behavioural interfaces and traits.
>
> -Dave


There's technically nothing you cannot do with any language once it has type 
definitions, functions, and closures.  Everything beyond that is syntactic 
sugar; including classes themselves.  It's a question of which syntactic sugar 
gives the sweetest developer experience.

The core question here is a little philosophical.  What exactly is an 
interface?  Is it "a collection of methods", "a collection of behaviors", or 
"how I can interact with this object"?

If you start from the position that an interface is "a collection of methods", 
then yes, interface properties don't fit.  However, I'd that's a 
too-restrictive understanding of interfaces.  "How can I interact with this 
object" or "what contracts, in the abstract, does this object fulfill" are more 
accurate questions answered by an interface.

There is a common but naive approach to OOP (which I have expressed myself in 
the past, so no shade involved here) that "properties are implementation, 
methods are abstraction."  Which... is not unreasonable as a first-order 
approximation, but is incomplete.

If your class has getters/setters (as is common for entities), then there's 
really no "implementation hiding" going on.  There's just extra syntax for a 
public property.  So the existence of those properties is already, de facto, a 
part of the interface of the object.  While you can fake it out with a 
different implementation inside the get/set methods (as in the various examples 
in the Property Hooks RFC), in practice it's quite rare to do so.  So that 
clean dividing line is already violated by common practice.

So on one level, property hooks and interface properties together let you 
define the behavior of an object similar to how you do now, but with 1/4 as 
much code, and without losing the ability to "fake it out" in the few cases 
it's necessary.  It's not violating any separation that isn't already violated 
in practice.

Moreover, methods obviously have their own implementation details.  While 
ideally those are kept fully separated from the outside world, in practice 
that's impossible.  Even if you had an Idris-level type system (with dependent 
types), you cannot completely specify all behavior in just an interface; If you 
could, it wouldn't be a type system anymore, just code. :-)  So the separation 
is not perfect on that side, either.

On another level, I'd redefine properties and methods slightly.  (Public) 
Properties are not "raw data" but "aspects of the object I can manipulate" and 
methods are "behaviors I can ask the object to perform."

>From that perspective (which seems to be increasingly common, based on the 
>listed languages that have some version of interface properties and 
>hooks/accessors), of course properties belong in interfaces.  It's obvious 
>that they do, because "aspect I can manipulate" is an abstract concept.

$collection->isEmpty() and $collection->isEmpty are both entirely reasonable 
ways to introspect the status of the $collection object.  There's nothing 
inherently superior about the former, except that historically it's been the 
only option.  Once you have hooks, though, the latter is a natural and obvious 
introspection mechanism.  I'm not suggesting it's superior or that anyone needs 
to switch to it, just that it's a reasonable approach.

And in that case, you need a reasonable way to specify that mechanism for an 
interface.  Hence, interface properties.

A "raw data" property can and should still be protected or private, at which 
point none of this discussion matters at all as those are not and should not be 
supported by interfaces.

--Larry Garfield

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php

Reply via email to