Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:120785 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 13959 invoked from network); 11 Jul 2023 22:02:03 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 11 Jul 2023 22:02:03 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 36F7A1804D0 for ; Tue, 11 Jul 2023 15:02:02 -0700 (PDT) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-1.3 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RDNS_NONE,SPF_HELO_NONE, SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS701 96.241.0.0/16 X-Spam-Virus: No X-Envelope-From: Received: from nebula.zort.net (unknown [96.241.205.3]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Tue, 11 Jul 2023 15:02:01 -0700 (PDT) Received: from smtpclient.apple (pulsar.zort.net [96.241.205.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by nebula.zort.net (Postfix) with ESMTPSA id 69FD62005D60D; Tue, 11 Jul 2023 18:02:00 -0400 (EDT) DKIM-Filter: OpenDKIM Filter v2.11.0 nebula.zort.net 69FD62005D60D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zort.net; s=zort; t=1689112920; bh=TcqhfFbAsrKKZQiRXjeubBXbgLpyid+DfcoMULh697I=; h=Subject:From:In-Reply-To:Date:Cc:References:To:From; b=fNS359rUhRl/Ht1wm7bGXQJLY7vW+pqDuEfUIj2Fcx7u/+Jvw7nWHf5ynl5cL6wne NPstni+XkOxMA0/cLJOlu2JbllvAsRfNbm7w4NAn9/obVu6FrYUA0rdqmIuAAxNSL+ VC1Kc+DTXnNWoeDZ0+ZdQJ39VuH5bb90ze55a5ho= Content-Type: text/plain; charset=us-ascii Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3731.600.7\)) In-Reply-To: Date: Tue, 11 Jul 2023 18:01:50 -0400 Cc: php internals Content-Transfer-Encoding: quoted-printable Message-ID: <549A1C48-64E8-4372-83D5-BF61C43C5430@zort.net> References: <3a3e7781-c2b4-2880-8048-d19458ac287d@heigl.org> <308d32d6-c145-4f8c-8779-101a696b60a0@app.fastmail.com> <66e67efa-1f41-4971-b070-7785f99ab286@app.fastmail.com> To: Larry Garfield , Robert Landers X-Mailer: Apple Mail (2.3731.600.7) Subject: Re: [PHP-DEV] [VOTE] Interface Default Methods From: jbafford@zort.net (John Bafford) On Jul 11, 2023, at 13:42, Larry Garfield = wrote: >=20 > On Tue, Jul 11, 2023, at 5:28 PM, Robert Landers wrote: >>=20 >> IMHO, using a shared base class reflects the inheritance better >> because they are siblings (at least these appear to be logical >> siblings out of context, IMHO) and should look like siblings in a >> class diagram. Their current dis-jointed-ness strikes me as odd and >> the usage of traits in this way strikes me as an anti-pattern. But I >> came from a PHP world where traits were nearly forbidden or used very >> sparingly. >=20 > Traits are a surgical tool with a narrow set of uses, and systems that = over-use them cause problems. (You know which framework you are...) = But this is one of their main valid uses. >=20 > In context, the classes are not siblings, and it would be incorrect = for them to extent from a base class. They just both happen to = implement the same *interface*, but that the same as having the same "is = a special case of" relationship with a base class. >=20 > Having a common base class instead would, as noted before, mean as = soon as I added a third "carries" option, I'd have to add four more base = classes to cover all combinations. It quickly gets absurd, and those = base classes have no valid type usage; they're purely there as an = alternative to copy-paste. >=20 > Using inheritance as an alternative to copy-paste is the wrong way(tm) = to do it. Both inheritance and copy-paste. Freshman CS classes still = love to talk about inheritance as a great thing for code reuse but... = it's really not, and many of the 21st century languages have been = drifting away from that. >=20 > Traits/default-method-interfaces are a better alternative that doesn't = conflate "copy-paste avoidance" with "is a special case of." Honestly, = I almost never use class inheritance in my greenfield code these days. =20= I'm stating my +1 for this feature (though I can't vote since I lack = vote karma), and also want to point that this is a feature in Swift as = well, and used extensively through its standard library. (The actual = mechanics are somewhat different, and significantly more powerful, both = for good and ill. I'm handwaving a bit to not get bogged down in details = that don't/can't matter for PHP.) A basic example in Swift's standard library is the Equatable and = Comparable interfaces. Both have partial implementations provided. = Between the two, if you implement the =3D=3D and < operations, the = stdlib provides !=3D, <=3D, >, and >=3D automatically, but you can = override them if desired by providing an explicit implementation. This = is used pretty much everywhere; most of the builtin types (like Int, = Float, String, and Array, which otherwise have no relation to each other = and definitely don't inherit from some base type) implement Equatable = and Comparable. Another example is the Sequence interface, which comes with a set of = default implementations for standard sequence algorithms, such as map, = first, min/max, contains, etc. This allows all types of sequences to = have the functionality expected of a sequence without needing to = redundantly implement basic operations (unless desired) or participate = in inheritance. This clear distinction between what a type _is_ (its type and = inheritance tree) and what a type _can do_ (the interfaces it = implements) is really important when you start piling on the interfaces. = Swift's standard library comes with a laundry list of interfaces that = provide partial or complete default implementations, and it's entirely = reasonable to combine these together. Consider, for example, a type that = implemented each of Sequence, Collection, Encodable, Decodable, = Equatable, and Hashable (such as Array or Dictionary). Creating a sane = inheritance tree for that would be difficult. (And that's before = considering that an array or dictionary should itself be = Encodable/Decodable/Equatable/Hashable if its elements (and keys) have = those properties. In Swift, the implementation for Array and Dictionary = is largely the details of managing data storage. Useful algorithms get = automatically inherited from default implementations from their many = interfaces without needing a common parent class for both arrays and = dictionaries, which are both structs which can't have inheritance = anyway.) I'll also point out that (in both PHP and Swift) enums can't participate = in inheritance, but can implement interfaces. If one wanted to provide a = default implementation for an interface used an enum, an abstract class = isn't an option at all. Anecdotally, outside of framework-mandated inheritance, the vast = majority of my types in Swift are structs, enums, and classes with no = inheritance, and many have interfaces that have some default = implementation provided. Most of my PHP classes that have inheritance = would be better served with interfaces + default implementations; they = use inheritance only because it is currently the least bad way to make = them work. Inheritance doesn't really capture the relationship between = them (which is that there is none, save for their shared interface). -John