Newsgroups: php.internals,php.internals Path: news.php.net Xref: news.php.net php.internals:84438 php.internals:84439 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 13106 invoked from network); 8 Mar 2015 15:45:53 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 8 Mar 2015 15:45:53 -0000 X-Host-Fingerprint: 78.217.8.218 gaz43-2-78-217-8-218.fbx.proxad.net Received: from [78.217.8.218] ([78.217.8.218:15078] helo=localhost.localdomain) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 6F/84-17427-0BE6CF45 for ; Sun, 08 Mar 2015 10:45:52 -0500 To: internals@lists.php.net,Rowan Collins , internals@lists.php.net Message-ID: <54FC6EAA.3050100@luni.fr> Date: Sun, 08 Mar 2015 16:45:46 +0100 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:31.0) Gecko/20100101 Thunderbird/31.4.0 MIME-Version: 1.0 References: <54FC29B4.4000105@luni.fr> <54FC5A71.7000905@gmail.com> In-Reply-To: <54FC5A71.7000905@gmail.com> Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit X-Posted-By: 78.217.8.218 Subject: Re: [PHP-DEV] Feature request and RFC From: gregory@luni.fr (=?UTF-8?B?R3LDqWdvcnkgUGxhbmNoYXQ=?=) Le 08/03/2015 15:19, Rowan Collins a écrit : > On 08/03/2015 10:51, Grégory Planchat wrote: >> Le 24/02/2015 20:20, Thomas Gielfeldt a écrit : >>> 2015-02-24 17:36 GMT+01:00 Benjamin Eberlei : >>> >>>> Hi, >>>> >>>> On Tue, Feb 24, 2015 at 5:17 PM, Thomas Gielfeldt >>>> wrote: >>>> >>>>> Hi internals. >>>>> >>>>> I've made PR proposing a feature request: A new interface Sortable. >>>>> >>>>> https://github.com/php/php-src/pull/1116 >>>>> >>>>> If possible, I would like to create and RFC describing this in more >>>>> detail, >>>>> and perhaps get a voting on. >>>>> >>>> >>>> so you need to implement all methods? This can probably be considered a >>>> violation of the Interface Segregation Principle. But adding an >>>> interface >>>> for each method seems a bit much as well. >>>> >>> >>> Yeah, I've thought of this as well. PHP has got a load of sort >>> functions. >>> I've also considered other options: >>> >>> 1.) 5 interfaces for, respectively, (r)sort, a(r)sort, k(r)sort, >>> u(a|k)sort >>> and nat(case)sort, with 2-3 methods per interface. >>> 2.) Same as above, but with a flag for reverse instead of a dedicated >>> function resulting in 5 interfaces with 1-3 methods each. >>> 3.) 1 interface with 2 methods, sort() and usort(), and flags for >>> reverse, >>> key and maintaining index. >>> >>> I did consider the latter much, but wasn't sure if the methods would get >>> too monolithic. >>> >>> I also did consider an interface per method. Briefly. :-) >>> >>> >>> >>>> >>>>> Thanks >>>>> >>>>> Br, >>>>> >>>>> Thomas Gielfeldt >>>>> >>>> >>>> >>> >> >> Hi, >> >> I posted a message in the discussion about function names consistency >> which is, in part, related to this thread. The main subject may be >> defining a consistent API, but one part is about ordering native arrays. >> >> http://news.php.net/php.internals/84429 >> >> I started to write some documentation for an OO API dedicated to >> arrays - and hence sorting arrays. >> >> https://github.com/gplanchat/php-oop-api/blob/master/doc/array-sorter.md >> >> I wrote in this document an abstract method, named SplArraySorter, >> which only has an abstract sort() method. Every variant implements the >> functionalities of one or multiple array sorting native functions. >> >> The point I want to come after is that the collection should not be >> aware of how we would want to sort it, but let this control to a >> external object. >> >> Therefore, the way collections may be actually sorted would become >> dependent on an external object and be changed on the fly by the >> program itself, without having to rewrite any line of code. This has >> the avantage of letting you have the control over any source code, >> whether you are the author (or able to change it) or if this code >> comes from a dependency (PEAR, Composer, ect...). >> >> So, to make it more visual, I would suggest intead to create the 2 >> interfaces Sorter and Sortable, which could be vritten as : >> >> > >> interface Sortable >> { >> } >> >> interface Sorter >> { >> public function sort(Sortable $collection); >> } > > > Empty interfaces are fine for extension-built objects, which under the > hood implement some particular data structure or whatever that the > implementation expects, but they're useless for userland classes, > because there's no way to actually implement them. > > If I have a class called UserList, and I want to make it sortable, how > do I do that with this setup? Again, thinking about different use cases > might help pin down where this approach would and wouldn't be useful. > > Regards, > Yes, I agree there is a missing part in the proposed implementation. So, let me change my previous definition to this meta-code: interface Sortable { } interface SortableAggregate extends Sortable { public function sort(Sorter $sorter); } interface SortableCollection extends Sortable, Traversable { public function swap(mixed $leftKey, mixed $rightKey); } interface Sorter { public function sort(Sortable $collection); } Then, this is example 1, using the interface SortableCollection: class Foo implements SortableCollection { private $internalCollection = []; public function swap(mixed $leftKey, mixed $rightKey) { /* * I assume a function like array_swap() would be more * appropriate as long as it already exists in the engine * and presumably not so difficult to bring to the * userspace anyway, but it currently does not exist */ $tmp = $this->internalCollection[$leftKey]; $this->internalCollection[$leftKey] = $this->internalCollection[$rightKey]; $this->internalCollection[$rightKey] = $tmp; } } class BarSortable implements Sorter { public function sort(Sortable $collection) { $previousKey = null; $previousElement = null; foreach ($collection as $key => $element) { if ($previousKey === null) { $previousKey = $key; $previousElement = $element; continue; } if ($previousElement < element) { $collection->swap($previousKey, $key); } $previousKey = $key; $previousElement = $element; } } } Then, this is example 2, using the interface SortableAggregate: class Baz implements SortableAggregate { private $internalCollection; public function __construct() { $this->internalCollection = new YourRandomSortedDataStructure(); } public function sort(Sorter $sorter) { $sorter->sort($collection); } } class BarSortable implements Sorter { private $internalSorter; public function __construct() { $this->internalSorter = new YourUsefulSorter(); } public function sort(Sortable $collection) { $collection->sort($this->internalSorter); } } By this way, with a swap() method, we let to the user-land code a way to map his internal implementation to the core array/SPL datastructure implementation. It just has to specify the keys in the collection to swap. The rules are then defined by the Sorter object. I assume there will be a big issue at start : the swap() method does not exist anywhere, neither on array nor on SPL data structures (nor other structures). Tell me if I you see any issues. Grégory Planchat