# Feature request and RFC

- Thread: https://externals.io/message/83674
- Original archive: https://news-web.php.net/php.internals/83674
- Started by Thomas Gielfeldt on 2015-02-24T16:17:25+00:00
- Messages: 28
- Page 1 of 2: messages 1 to 25 (25 per page, add `?page=N` to the URL)
- Next page: https://externals.io/message/83674.md?page=2
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #83674 — Thomas Gielfeldt — 2015-02-24T16:17:25+00:00

URL: https://externals.io/message/83674#83674

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.

Thanks

Br,

Thomas Gielfeldt

---

## #83676 — Benjamin Eberlei — 2015-02-24T16:36:28+00:00

URL: https://externals.io/message/83674#83676 · In reply to: #83674

Hi,

On Tue, Feb 24, 2015 at 5:17 PM, Thomas Gielfeldt <thomas@gielfeldt.dk>
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.

>
> Thanks
>
> Br,
>
> Thomas Gielfeldt

---

## #83685 — Thomas Gielfeldt — 2015-02-24T19:20:19+00:00

URL: https://externals.io/message/83674#83685 · In reply to: #83676

2015-02-24 17:36 GMT+01:00 Benjamin Eberlei <kontakt@beberlei.de>:

> Hi,
>
> On Tue, Feb 24, 2015 at 5:17 PM, Thomas Gielfeldt <thomas@gielfeldt.dk>
> wrote:
>
> > […]
>
> 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. :-)



>
> > […]

---

## #83693 — Stanislav Malyshev — 2015-02-24T19:49:05+00:00

URL: https://externals.io/message/83674#83693 · In reply to: #83674

Hi!

> 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.

Can't you sort any class that provides ordered list of elements and
Comparable or some kind of comparison callback by a generic algorithm?
Interface with 11 functions, all similar but slightly different, seems
unoptimal.

-- 
Stas Malyshev
smalyshev@gmail.com

---

## #83695 — Thomas Gielfeldt — 2015-02-24T20:04:53+00:00

URL: https://externals.io/message/83674#83695 · In reply to: #83693

2015-02-24 20:49 GMT+01:00 Stanislav Malyshev <smalyshev@gmail.com>:

> Hi!
>
> > […]
> detail,
> > […]
>
> Can't you sort any class that provides ordered list of elements and
> Comparable or some kind of comparison callback by a generic algorithm?
> Interface with 11 functions, all similar but slightly different, seems
> unoptimal.
>
> One of the goals of this, is to make at it possible to use the Xsort()
functions on objects. I agree, implementing 11 methods might be
sub-optimal. We could reduce it to 2 methods, and then provide flags for
the variations.

--
> Stas Malyshev
> smalyshev@gmail.com

---

## #83759 — Thomas Gielfeldt — 2015-02-25T10:21:29+00:00

URL: https://externals.io/message/83674#83759 · In reply to: #83676

2015-02-24 17:36 GMT+01:00 Benjamin Eberlei <kontakt@beberlei.de>:

> Hi,
>
> On Tue, Feb 24, 2015 at 5:17 PM, Thomas Gielfeldt <thomas@gielfeldt.dk>
> wrote:
>
> > […]
>
> 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.
>
> > […]
I have some more proposals for how to implement this interface. Should we
create an RFC for purposes of discussion, or do you usually do this in the
mailing lists?

1 interface with 2 methods, controlled by flags.

/** @ingroup SPL
 * @brief This Interface allows to hook into the global `sort()` functions.
 * @since PHP 5.1
 */
interface Sortable
{
  /**
   * Sort values or keys.
   * @param int $flags
   *   `SORT_REGULAR` 
   *   `SORT_NUMERIC` 
   *   `SORT_STRING` 
   *   `SORT_LOCALE_STRING` 
   *   `SORT_NATURAL` 
   *   -- bitwise flags
   *   SORT_SORT_FLAG_CASE - case insensitive sorting.
   *   SORT_REVERSE - sort in reverse.
   *   SORT_KEYS - sort keys.
   *   SORT_INDEX - maintain indexes.
   * @return bool
   *   `TRUE` on success.
   */
  function sort($flags);

  /**
   * Sort values or keys.
   * @param callback $cmp_function
   *   Compare callback
   * @return bool
   *   `TRUE` on success.
   */
  function usort($cmp_function);
}


-----------------------------


4 interfaces with 1 method, controlled by flags.

/** @ingroup SPL
 * @brief This Interface allows to hook into the global `sort()` functions.
 * @since PHP 5.1
 */
interface Sortable
{
  /**
   * Sort values.
   * @param int $flags
   *   `SORT_REGULAR` 
   *   `SORT_NUMERIC` 
   *   `SORT_STRING` 
   *   `SORT_LOCALE_STRING` 
   *   `SORT_NATURAL` 
   *   -- bitwise flags
   *   SORT_SORT_FLAG_CASE - case insensitive sorting.
   *   SORT_REVERSE - sort in reverse.
   * @return bool
   *   `TRUE` on success.
   */
  function sort($flags);
}

/** @ingroup SPL
 * @brief This Interface allows to hook into the global aXsort() functions.
 * @since PHP 5.1
 */
interface SortableIndex
{
  /**
   * Sort values and maintain index association.
   * @param int $flags
   *   `SORT_REGULAR` 
   *   `SORT_NUMERIC` 
   *   `SORT_STRING` 
   *   `SORT_LOCALE_STRING` 
   *   `SORT_NATURAL` 
   *   -- bitwise flags
   *   SORT_SORT_FLAG_CASE - case insensitive sorting.
   *   SORT_REVERSE - sort in reverse.
   * @return bool
   *   `TRUE` on success.
   */
  function asort($flags);
}

/** @ingroup SPL
 * @brief This Interface allows to hook into the global kXsort() functions.
 * @since PHP 5.1
 */
interface SortableKeys
{
  /**
   * Sort keys.
   * @param int $flags
   *   `SORT_REGULAR` 
   *   `SORT_NUMERIC` 
   *   `SORT_STRING` 
   *   `SORT_LOCALE_STRING` 
   *   `SORT_NATURAL` 
   *   -- bitwise flags
   *   SORT_SORT_FLAG_CASE - case insensitive sorting.
   *   SORT_REVERSE - sort in reverse.
   * @return bool
   *   `TRUE` on success.
   */
  function ksort($flags);
}

/** @ingroup SPL
 * @brief This Interface allows to hook into the global uXsort() functions.
 * @since PHP 5.1
 */
interface SortableUser
{
  /**
   * Sort values or keys.
   * @param callback $cmp_function
   *   Compare callback
   * @return bool
   *   `TRUE` on success.
   */
  function usort($cmp_function);
}


The `natsort()` and `natcasesort()` can already be covered by `sort()` through
flags, so I think we should leave them out.




> Thanks
> > […]

---

## #83761 — Alexander Lisachenko — 2015-02-25T10:31:58+00:00

URL: https://externals.io/message/83674#83761 · In reply to: #83759

2015-02-25 13:21 GMT+03:00 Thomas Gielfeldt <thomas@gielfeldt.dk>:

> I have some more proposals for how to implement this interface. Should we
> create an RFC for purposes of discussion, or do you usually do this in the
> mailing lists?
>


Best interface is described by the one single method: `sort()` that accepts
optional flags and callback function:

So,

interface Sortable {
    const ASC = 1;
    const DESC = 2;
    const `SORT_REGULAR` = 4;
    const `SORT_NUMERIC` = 8;
    // more consts here...

    public function sort($flags = 0, callable $callback = null);
}

Callback will accept key and value pair.

---

## #83762 — Thomas Gielfeldt — 2015-02-25T10:37:06+00:00

URL: https://externals.io/message/83674#83762 · In reply to: #83761

2015-02-25 11:31 GMT+01:00 Alexander Lisachenko <lisachenko.it@gmail.com>:

>
> 2015-02-25 13:21 GMT+03:00 Thomas Gielfeldt <thomas@gielfeldt.dk>:
>
> > […]
>
>
> Best interface is described by the one single method: `sort()` that accepts
> optional flags and callback function:
>
> So,
>
> interface Sortable {
>     const ASC = 1;
>     const DESC = 2;
>     const `SORT_REGULAR` = 4;
>     const `SORT_NUMERIC` = 8;
>     // more consts here...
>
>     public function sort($flags = 0, callable $callback = null);
> }
>
> Callback will accept key and value pair.
>

Yeah, but the "problem" with this, is that your class' sort method, you
have to implement all the possible permutations the flags can produce. This
basically just squeezes the 11 functions into 1. The 1 interface with
 `sort()` and `usort()` splits this into 2 functions (8+3). With that in mind,
I'm more inclined to choose the 4 interface approach.

---

## #83765 — Alexander Lisachenko — 2015-02-25T11:15:30+00:00

URL: https://externals.io/message/83674#83765 · In reply to: #83762

2015-02-25 13:37 GMT+03:00 Thomas Gielfeldt <thomas@gielfeldt.dk>:

> Yeah, but the "problem" with this, is that your class' sort method, you
> have to implement all the possible permutations the flags can produce. This
> basically just squeezes the 11 functions into 1. The 1 interface with
> `sort()` and `usort()` splits this into 2 functions (8+3). With that in mind,
> I'm more inclined to choose the 4 interface approach.



For that case, move all configurations to the several classes and configure
these flags in the concrete constructors. Interface will be more simple:

interface Sortable {
    const ASC = 1;
    const DESC = 2;

    public function sort($direction = self::ASC, callable $callback = null);
}

class KeySorter implements Sortable {}

---

## #83768 — Thomas Gielfeldt — 2015-02-25T11:42:15+00:00

URL: https://externals.io/message/83674#83768 · In reply to: #83765

2015-02-25 12:15 GMT+01:00 Alexander Lisachenko <lisachenko.it@gmail.com>:

>
> 2015-02-25 13:37 GMT+03:00 Thomas Gielfeldt <thomas@gielfeldt.dk>:
>
> > […]
>
>
>
> For that case, move all configurations to the several classes and
> configure these flags in the concrete constructors. Interface will be more
> simple:
>
> interface Sortable {
>     const ASC = 1;
>     const DESC = 2;
>
>     public function sort($direction = self::ASC, callable $callback =
> null);
> }
>
> class KeySorter implements Sortable {}
>

That seems a little backwards to me? How would the consumer of e.g.
KeySorter know which sort variations are implemented?

---

## #83870 — Thomas Gielfeldt — 2015-02-26T06:36:09+00:00

URL: https://externals.io/message/83674#83870 · In reply to: #83676

2015-02-24 17:36 GMT+01:00 Benjamin Eberlei <kontakt@beberlei.de>:

> Hi,
>
> On Tue, Feb 24, 2015 at 5:17 PM, Thomas Gielfeldt <thomas@gielfeldt.dk>
> wrote:
>
> > […]
>
> 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.
>
> > […]
Another solution could be:

/** @ingroup SPL
 * @brief This Interface allows to hook into the global Xsort() functions.
 * @since PHP 5.6
 */
interface Sortable
{
  /**
   * Sort the entries by values.
   *
   * @param integer $sort_flags
   *   SORT_REGULAR:       compare items normally (don't change types)
   *   SORT_NUMERIC:       compare items numerically
   *   SORT_STRING:        compare items as strings
   *   SORT_LOCALE_STRING: compare items as strings, based on the current
locale. It uses the locale, which can be changed using `setlocale()`
   *   SORT_NATURAL:       compare items as strings using "natural
ordering" like `natsort()`
   *   SORT_FLAG_CASE:     can be combined (bitwise OR) with `SORT_STRING` or
 `SORT_NATURAL` to sort strings case-insensitively
   *   SORT_FLAG_REVERSE:  can be combined (bitwise OR) with any of the
other options to sort in reverse
   */
  function sort($sort_flags = SORT_REGULAR);

  /** Sort the entries by values using user defined function.
   */
  function usort(mixed cmp_function);
}


/** @ingroup SPL
 * @brief This Interface allows to hook into the global XaXsort() functions.
 * @since PHP 5.6
 */
interface SortableAssoc
{
  /**
   * Sort the entries by values and maintain indexes.
   *
   * @param integer $sort_flags
   *   SORT_REGULAR:       compare items normally (don't change types)
   *   SORT_NUMERIC:       compare items numerically
   *   SORT_STRING:        compare items as strings
   *   SORT_LOCALE_STRING: compare items as strings, based on the current
locale. It uses the locale, which can be changed using `setlocale()`
   *   SORT_NATURAL:       compare items as strings using "natural
ordering" like `natsort()`
   *   SORT_FLAG_CASE:     can be combined (bitwise OR) with `SORT_STRING` or
 `SORT_NATURAL` to sort strings case-insensitively
   *   SORT_FLAG_REVERSE:  can be combined (bitwise OR) with any of the
other options to sort in reverse
   */
  function asort($sort_flags = SORT_REGULAR);

  /** Sort the entries by values using user defined function and maintain
index.
   */
  function uasort(mixed cmp_function);
}

/** @ingroup SPL
 * @brief This Interface allows to hook into the global XkXsort() functions.
 * @since PHP 5.6
 */
interface SortableKeys
{
  /**
   * Sort the entries by key.
   *
   * @param integer $sort_flags
   *   SORT_REGULAR:       compare items normally (don't change types)
   *   SORT_NUMERIC:       compare items numerically
   *   SORT_STRING:        compare items as strings
   *   SORT_LOCALE_STRING: compare items as strings, based on the current
locale. It uses the locale, which can be changed using `setlocale()`
   *   SORT_NATURAL:       compare items as strings using "natural
ordering" like `natsort()`
   *   SORT_FLAG_CASE:     can be combined (bitwise OR) with `SORT_STRING` or
 `SORT_NATURAL` to sort strings case-insensitively
   *   SORT_FLAG_REVERSE:  can be combined (bitwise OR) with any of the
other options to sort in reverse
   */
  function ksort($sort_flags = SORT_REGULAR);

  /** Sort the entries by key using user defined function.
   */
  function uksort(mixed cmp_function);
}


I have a working implementation of this also.


> Thanks
> > […]

---

## #83945 — Thomas Gielfeldt — 2015-02-27T01:28:18+00:00

URL: https://externals.io/message/83674#83945 · In reply to: #83676

2015-02-24 17:36 GMT+01:00 Benjamin Eberlei <kontakt@beberlei.de>:

> Hi,
>
> On Tue, Feb 24, 2015 at 5:17 PM, Thomas Gielfeldt <thomas@gielfeldt.dk>
> wrote:
>
> > […]
>
> 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.
>

I've made another PR to show a different implementation. I've also
registered a wiki account. I don't have access to create an RFC for this.
I'm not actually sure how to go about this?

https://github.com/php/php-src/pull/1123


> > […]

---

## #83995 — Rowan Collins — 2015-02-27T12:28:28+00:00

URL: https://externals.io/message/83674#83995 · In reply to: #83674

Thomas Gielfeldt wrote on 24/02/2015 16:17:
> 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.

I think the reason this interface is proving hard to simplify is that 
you're putting too much of the responsibility on the implementing 
object. Most containers don't need or want to reimplement an entire 
quicksort algorithm, or be responsible for tracking the various types of 
comparison.

Ideally, you could start by writing an OO implementation of QuickSort 
which takes as its input an abstract "Collection" instead of an array, 
and look at what methods you end up wanting to call on that Collection. 
That might end up rather complex in practice, though, because the 
underlying data structures do make a difference to an efficient 
implementation.

However, the types of sort differ primarily in the way values are 
compared, so if the engine passed in an appropriate comparison callback, 
the interface needs only one method:

public function sort(callable $comparison_callback, boolean $preserve_keys)
where $comparison_callback is:
function($l_key, $l_value, $r_key, $r_value): int

The only flag that the object might want to care about is whether to 
preserve keys (asort, uasort, ksort, uksort), because it could allow 
optimisations rather than reindexing after the sort has completed. For 
everything else, it should just be repeatedly asking the engine "which 
of these two items should come first?" By passing both keys and values, 
 `ksort()` can be implemented with the same callback signature, the only 
disadvantage being that the user callbacks to `usort()` and `uksort()` would 
need to be wrapped, with the engine basically emulating the following:

// For usort($object, $usort_callback)
$comparison_callback = function($l_key, $l_value, $r_key, $r_value) use 
($usort_callback) { return $usort_callback($l_value, $r_value); };
// For ksort($object, $ksort_callback)
$comparison_callback = function($l_key, $l_value, $r_key, $r_value) use 
($ksort_callback) { return $ksort_callback($l_key, $r_key); };

Regards,
-- 
Rowan Collins
[IMSoP]

---

## #84148 — Thomas Gielfeldt — 2015-03-02T07:43:13+00:00

URL: https://externals.io/message/83674#84148 · In reply to: #83674

2015-02-24 17:17 GMT+01:00 Thomas Gielfeldt <thomas@gielfeldt.dk>:

> 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.
>
> Thanks
>
> Br,
>
> Thomas Gielfeldt
>
>
The 2nd PR I made addresses this (https://github.com/php/php-src/pull/1123),
exposing 3 much simpler interfaces depending on what the user wants/needs
to implement, which combined covers all the 11 sort functions.

Also, the point of this/these interface(s) is to provide the same power
that some of the other SPL interfaces have (Countable, Serializable,
ArrayAccess, Iterator, etc.). That is, using native functions with objects
possessing certain capabilities.

---

## #84164 — Rowan Collins — 2015-03-02T10:52:22+00:00

URL: https://externals.io/message/83674#84164 · In reply to: #84148

Thomas Gielfeldt wrote on 02/03/2015 07:43:
> 2015-02-24 17:17 GMT+01:00 Thomas Gielfeldt <thomas@gielfeldt.dk>:
>
> > […]
> The 2nd PR I made addresses this (https://github.com/php/php-src/pull/1123),
> exposing 3 much simpler interfaces depending on what the user wants/needs
> to implement, which combined covers all the 11 sort functions.
>
> Also, the point of this/these interface(s) is to provide the same power
> that some of the other SPL interfaces have (Countable, Serializable,
> ArrayAccess, Iterator, etc.). That is, using native functions with objects
> possessing certain capabilities.


I don't think a container should be expected to reimplement something as 
specific as a case-insensitive natural string comparison; its job should 
be to do the actual sorting of data.

I suggest a single interface with 3 methods: sortValues($cmp_function), 
sortValuesAssoc($cmp_function), and sortKeys($cmp_function): 
https://gist.github.com/IMSoP/4ea904203eadf8d5859a

This maintains the obvious connection between userland functions and the 
method called, and keeps the userland implementation much lower on 
boilerplate. Conveniently, a collection which internally stores data in 
an array can pass the callback directly to usort/uasort/uksort for a 
trivial implementation.

Obviously, this means more implementation needed on the engine side, in 
that it needs to expose callback functions for the various different 
comparisons, but I think that's where the comparison logic belongs.

Regards,
-- 
Rowan Collins
[IMSoP]

---

## #84171 — Rowan Collins — 2015-03-02T15:26:00+00:00

URL: https://externals.io/message/83674#84171 · In reply to: #84164

Rowan Collins wrote on 02/03/2015 10:52:
> Thomas Gielfeldt wrote on 02/03/2015 07:43:
> > […]
>
>
> I don't think a container should be expected to reimplement something 
> as specific as a case-insensitive natural string comparison; its job 
> should be to do the actual sorting of data.
>
> I suggest a single interface with 3 methods: 
> sortValues($cmp_function), sortValuesAssoc($cmp_function), and 
> sortKeys($cmp_function): 
> https://gist.github.com/IMSoP/4ea904203eadf8d5859a
>
> This maintains the obvious connection between userland functions and 
> the method called, and keeps the userland implementation much lower on 
> boilerplate. Conveniently, a collection which internally stores data 
> in an array can pass the callback directly to usort/uasort/uksort for 
> a trivial implementation.
>
> Obviously, this means more implementation needed on the engine side, 
> in that it needs to expose callback functions for the various 
> different comparisons, but I think that's where the comparison logic 
> belongs.


Incidentally, note that this is exactly how the sorting of real arrays 
is done internally: zend_hash_sort_ex [1] takes a comparison callback, 
using a global set by php_set_compare_func [2] for flags, and wrappers 
for things like key vs data comparison [3].

Basically, to implement my suggestion, you need a way to expose the 
php_array_*_compare functions in ext/standard/array.c as callbacks to 
userland, presumably without actually making them named functions.


[1] http://lxr.php.net/xref/PHP_TRUNK/Zend/zend_hash.c#1930
[2] http://lxr.php.net/xref/PHP_TRUNK/ext/standard/array.c#144
[3] http://lxr.php.net/xref/PHP_TRUNK/ext/standard/array.c#173

Regards,
-- 
Rowan Collins
[IMSoP]

---

## #84275 — Thomas Gielfeldt — 2015-03-04T07:12:41+00:00

URL: https://externals.io/message/83674#84275 · In reply to: #84171

2015-03-02 16:26 GMT+01:00 Rowan Collins <rowan.collins@gmail.com>:

> Rowan Collins wrote on 02/03/2015 10:52:
>
> > […]
>
>
> Incidentally, note that this is exactly how the sorting of real arrays is
> done internally: zend_hash_sort_ex [1] takes a comparison callback, using a
> global set by php_set_compare_func [2] for flags, and wrappers for things
> like key vs data comparison [3].
>
> Basically, to implement my suggestion, you need a way to expose the
> php_array_*_compare functions in ext/standard/array.c as callbacks to
> userland, presumably without actually making them named functions.
>
>
Though I can appreciate the elegance in what you propose, I'm worried about
a couple of things with this approach.

1.) Having to pass a comparison function through userland, could hurt
performance for the ArrayObject, which otherwise would use the native C
sort functions directly on its hashtable.

2.) This approach forces the implementor to rely on a userland comparison
function. While this would not be a problem for the specific use case I had
in mind, it could destroy the possibility of further abstraction. One
example could be a sort in conjunction with a database class. Probably not
the best example, but I hope you understand what I'm getting at.
Dispatching the sort to something outside PHP. If all that the sort methods
get are closures, then it's near impossible to determine the intent of the
caller.

3.) I'm probably gonna the one implementing this, and I think this approach
would be much more complex than the two I've already made :-) ... though,
of course, that's not an excuse :-)


That being said, I still like the approach you suggest wrt responsibility
of the interface. I just think that there may be some practical
implications.



>
> [1] http://lxr.php.net/xref/PHP_TRUNK/Zend/zend_hash.c#1930
> [2] http://lxr.php.net/xref/PHP_TRUNK/ext/standard/array.c#144
> [3] http://lxr.php.net/xref/PHP_TRUNK/ext/standard/array.c#173
>
> Regards,
> --
> Rowan Collins
> [IMSoP]

---

## #84284 — Rowan Collins — 2015-03-04T09:41:16+00:00

URL: https://externals.io/message/83674#84284 · In reply to: #84275

>2015-03-02 16:26 GMT+01:00 Rowan Collins <rowan.collins@gmail.com>:
>
> > […]
>Sortable.
> > […]
>more
> > […]
>wants/needs
> > […]
>power
> > […]
>Serializable,
> > […]
>something as
> > […]
>should be
> > […]
>sortValues($cmp_function),
> > […]
>the
> > […]
>in an
> > […]
>trivial
> > […]
>in
> > […]
>arrays is
> > […]
>using a
> > […]
>things
> > […]
>Though I can appreciate the elegance in what you propose, I'm worried
>about
>a couple of things with this approach.
>
>1.) Having to pass a comparison function through userland, could hurt
>performance for the ArrayObject, which otherwise would use the native C
>sort functions directly on its hashtable.

Anything implemented in a C extension can still do so, just as they can overload property access or Traversable behaviour. This interface is only necessary when implementing the sort logic in userland anyway.

>2.) This approach forces the implementor to rely on a userland
>comparison
>function. While this would not be a problem for the specific use case I
>had
>in mind, it could destroy the possibility of further abstraction. One
>example could be a sort in conjunction with a database class. Probably
>not
>the best example, but I hope you understand what I'm getting at.
>Dispatching the sort to something outside PHP. If all that the sort
>methods
>get are closures, then it's near impossible to determine the intent of
>the
>caller.

Hm, yes, I hadn't thought of the use case of sorting external data. Perhaps we actually need to specify both interfaces (yes, I realise I'm just inventing more work here, sorry!) - one for the use case of a custom data structure that wants to worry about the sort mechanics but not the ordering, and one for the different use case of wanting to sort something other than PHP values. I strongly believe that making the first type of object reimplement 11 types of comparison callback which the engine already has is a bad idea.

Regards,
-- 
Rowan Collins
[IMSoP]

---

## #84286 — Lester Caine — 2015-03-04T10:07:39+00:00

URL: https://externals.io/message/83674#84286 · In reply to: #84284

> Hm, yes, I hadn't thought of the use case of sorting external data. Perhaps we actually need to specify both interfaces (yes, I realise I'm just inventing more work here, sorry!) - one for the use case of a custom data structure that wants to worry about the sort mechanics but not the ordering, and one for the different use case of wanting to sort something other than PHP values. I strongly believe that making the first type of object reimplement 11 types of comparison callback which the engine already has is a bad idea.

I'd been following this thread, but only from a distant need. I tend to
be working with lists pulled directly from a database, and Firebird
allows the selection of collation rules to take care of the bulk of the
problems this interface is also trying to address. This option allows
all of the complication created by unicode to be addressed and a ready
sorted array is provided. The starting point for a generic approach
needs to be based on a unicode rule set which currently we do not have a
standard for. ICU provides a collation system in parallel with the
database standards and if the ICU based string object is adopted then
sort interfaces need to be based on that.

-- 
Lester Caine - G8HFL
-----------------------------
Contact - http://lsces.co.uk/wiki/?page=contact
L.S.Caine Electronic Services - http://lsces.co.uk
EnquirySolve - http://enquirysolve.com/
Model Engineers Digital Workshop - http://medw.co.uk
Rainbow Digital Media - http://rainbowdigitalmedia.co.uk

---

## #84426 — Thomas Gielfeldt — 2015-03-08T08:57:08+00:00

URL: https://externals.io/message/83674#84426 · In reply to: #84284

2015-03-04 10:41 GMT+01:00 Rowan Collins <rowan.collins@gmail.com>:

> On 4 March 2015 07:12:41 GMT, Thomas Gielfeldt <thomas@gielfeldt.dk>
> wrote:
> > […]
>
> Anything implemented in a C extension can still do so, just as they can
> overload property access or Traversable behaviour. This interface is only
> necessary when implementing the sort logic in userland anyway.
>
> > […]
>
> Hm, yes, I hadn't thought of the use case of sorting external data.
> Perhaps we actually need to specify both interfaces (yes, I realise I'm
> just inventing more work here, sorry!) - one for the use case of a custom
> data structure that wants to worry about the sort mechanics but not the
> ordering, and one for the different use case of wanting to sort something
> other than PHP values. I strongly believe that making the first type of
> object reimplement 11 types of comparison callback which the engine already
> has is a bad idea.
>
>
What about a "hybrid" solution? Pass the flags as well as a callback. Then
the implementor can react on the flags if necessary.

https://gist.github.com/gielfeldt/c0ca611f525878c36a65

In this case, I've introduced a new constant for user defined sort.
However, I see a couple of variations on this.

1.) Constant for determining user defined sort (as per the example).
2.) 2 methods, one for usorts, and one for the others (still with both
flags and callbacks). This will result in 6 methods, if we keep it to just
one interface.
3.) 3 interfaces with either one or two methods (option 1 & 2 above).


Regards,
> --
> Rowan Collins
> [IMSoP]

---

## #84427 — Lester Caine — 2015-03-08T09:27:38+00:00

URL: https://externals.io/message/83674#84427 · In reply to: #84426

> > […]
> What about a "hybrid" solution? Pass the flags as well as a callback. Then
> the implementor can react on the flags if necessary.
> 
> https://gist.github.com/gielfeldt/c0ca611f525878c36a65

Off topic I know - but how the **** do I make the github text readable?
Light grey on white may work for some, but even changing contrast on the
monitor I can't actually read that :(

> In this case, I've introduced a new constant for user defined sort.
> However, I see a couple of variations on this.
> 
> 1.) Constant for determining user defined sort (as per the example).
> 2.) 2 methods, one for usorts, and one for the others (still with both
> flags and callbacks). This will result in 6 methods, if we keep it to just
> one interface.
> 3.) 3 interfaces with either one or two methods (option 1 & 2 above).

-- 
Lester Caine - G8HFL
-----------------------------
Contact - http://lsces.co.uk/wiki/?page=contact
L.S.Caine Electronic Services - http://lsces.co.uk
EnquirySolve - http://enquirysolve.com/
Model Engineers Digital Workshop - http://medw.co.uk
Rainbow Digital Media - http://rainbowdigitalmedia.co.uk

---

## #84431 — gregory@luni.fr — 2015-03-08T10:51:32+00:00

URL: https://externals.io/message/83674#84431 · In reply to: #83685

Le 24/02/2015 20:20, Thomas Gielfeldt a écrit :
> 2015-02-24 17:36 GMT+01:00 Benjamin Eberlei <kontakt@beberlei.de>:
>
> > […]
>
> 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. :-)
>
>
>
> > […]
>

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 :

<?php

interface Sortable
{
}

interface Sorter
{
     public function sort(Sortable $collection);
}

Greetings

Grégory Planchat

---

## #84436 — Rowan Collins — 2015-03-08T14:03:26+00:00

URL: https://externals.io/message/83674#84436 · In reply to: #84286

> 
> > […]
> I'd been following this thread, but only from a distant need. I tend to
> be working with lists pulled directly from a database, and Firebird
> allows the selection of collation rules to take care of the bulk of the
> problems this interface is also trying to address. This option allows
> all of the complication created by unicode to be addressed and a ready
> sorted array is provided. The starting point for a generic approach
> needs to be based on a unicode rule set which currently we do not have a
> standard for. ICU provides a collation system in parallel with the
> database standards and if the ICU based string object is adopted then
> sort interfaces need to be based on that.


Actually, collation is an interesting point - of all the different sort 
functions in current PHP, none of them really considers it.

That's a disadvantage of passing the flags through to the collection 
being sorted, rather than the comparison implementation - it's very hard 
for us to change the underlying set of sort options without a BC break 
on the interface, because they're so closely coupled. For remote data 
sources, they'd need a new argument or method to accept and act on the 
new options; for simple data structures, they'd want to just use the new 
comparison type.

Like so many things, it's probably a good idea to consider up front the 
kinds of use cases we're targeting, and those that we're not, otherwise 
we end up with an implementation that is very well-engineered in itself, 
but doesn't actually meet people's needs.

Regards,

-- 
Rowan Collins
[IMSoP]

---

## #84437 — Rowan Collins — 2015-03-08T14:19:29+00:00

URL: https://externals.io/message/83674#84437 · In reply to: #84431

> Le 24/02/2015 20:20, Thomas Gielfeldt a écrit :
> > […]
>
> 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 :
>
> <?php
>
> 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,

-- 
Rowan Collins
[IMSoP]

---

## #84438 — gregory@luni.fr — 2015-03-08T15:45:46+00:00

URL: https://externals.io/message/83674#84438 · In reply to: #84437

Le 08/03/2015 15:19, Rowan Collins a écrit :
> 
> > […]
>
>
> 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

---

Next page: https://externals.io/message/83674.md?page=2
