rfc:any_all_on_iterable_straw_poll_namespace

This is an old revision of the document!


Straw poll: Using namespaces for *any() and *all() on iterables

Introduction

The primitives *any*() and *all*() are a common part of many programming languages and help in avoiding verbosity or unnecessary abstractions.

Before adding this, I'd like to see what others think about the choice of naming pattern. In a previous poll, the option iterable_any() was preferred over iter_any()/any(), but several responses were moderately or strongly in favor of namespaces.

  1. I plan to propose additional internal functions for working with iterables if this succeeds, and would want to be sure this is the best name choice going forwards.
  2. Additionally, this has been an opportunity for measuring overall interest in adopting namespaces for brand new categories of functionality - existing methods work on Traversables (iterator_*) or arrays (array_*), but generally not both.

https://externals.io/message/112558

From Levi Morrison:

I want to re-iterate my opinion on this discussion thread: anything with a prefix is a hard-no from me. Namespaces are literally designed for this, and I will not vote “yes” to iter_all, iterable_all, etc, no matter what the prefix is. Anything without a namespace is a no from me.

I'm flexible on many other points, but not this one. It's 2020 (almost 2021); let's use namespaces for what they were designed for. This is a perfect opportunity; they work on more than just arrays so using the array_ prefix for consistency doesn't apply.

https://externals.io/message/112558#112588

Hey Tyson,

I know I'm being stubborn, but we have namespaces, but also an “old guard” that doesn't understand its own programming language 🤷‍♀️

The main thing I'm concerned about is that once we start extending this area (I assume that any & all are not going to be the last additions in this space) we will quickly run into function names that are either too generic or outright collide. For example, what if we want to add an iterator-based version of range()? Do we really want to be forced to pull a Python and call it xrange()? That's about as good as real_range()...

As such, I think it's important to prefix these somehow, though I don't care strongly how. Could be iter_all() or iterable_all(). We might even make it iterator_all() if we also adjust other existing iterator_* functions to accept iterables. I'd also be happy with iter\all() or iterable\all(), but that gets us back into namespacing discussions :)

Regards, Nikita

Discussion

Choice of namespace

This poll includes one of the naming options suggested by Levi Morrison and uses the suggested namespace for alternative options.

I could start a second straw poll and wait for those results if you had a proposal for (a namespace) in mind.

Simply `Spl\all_values`. I don't think there's a need for another namespace component:

1) The SPL can disambiguate within itself.

2) It _shouldn't_ become the dumping ground of PHP.

Spl was chosen as a namespace because:

  1. Existing iterator/iterable functionality such as iterator_* and data structures were placed in the spl extension, and any/all would be as well.
  2. Existing classes are named SplObjectStorage, SplFixedArray, etc. (e.g. for ReflectionClass->getName()) - using the Spl casing would be consistent within the |spl module.
  3. It is less prone to conflicts than iter - e.g. https://github.com/nikic/iter.
  4. The Spl\ namespace can be reused for new classes/functions if they belong in the spl module. (I have no plans to move existing functions/classes to that namespace)

Future extension

It is possibly that functionality to check if any/all keys satisfy a predicate, or any/all combinations of entries add a predicate. If this gets added, there are two possibilities

  1. Add *any_key for keys, and *any_entry/*any_key_value() for key+value combination
  2. Add flags to the *any() method, like array_filter()

There's precedent for both choices of naming patterns, and I'm fine with either choice. Precedents include array_values() and array_keys(), as well as array_diff() and array_diff_keys()

Inconveniences of iterable\ in namespace

From https://externals.io/message/112558#112832

I've also realized that use prefix\iterable would be mildly inconvenient for users of PHP and for tooling (refactoring tools, IDEs, etc) for PHP, but still include it as an option because it's manageable and the non-namespaced prefix iterable_ was preferred in the previous poll.

php > namespace W { echo iterable::class; }
W\iterable
 
php > namespace X { use iterable; }
 
Fatal error: Cannot use iterable as iterable because 'iterable' is a special class name in php shell code on line 1
php > namespace X { use iterable\any; /* using individual functions works */ }
php > namespace Y { use PHP\iterable; function foo(iterable $x) {}}
 
Fatal error: Cannot use PHP\iterable as iterable because 'iterable' is a special class name in php shell code on line 1
php > namespace Z { use PHP\iterable as iter; }
php > namespace iterable { echo "can be polyfilled\n"; }
can be polyfilled

Vote

This vote will influence the name choice for the RFC https://wiki.php.net/rfc/any_all_on_iterable

This is a ranked-choice poll (following STV) between the naming alternatives.

With STV you SHOULD rank all the choices in order (but are not required to). Don't pick the same option more than once, as that invalidates your vote.

Straw poll: Favorite choice of namespace
Real name iterable_any() and iterable_all() iter\ iterable\ PHP\ PHP\iter\ PHP\iterable\ Ext\Spl\ Spl\ Spl\iter\ Spl\iterable\
alec (alec)          
as (as)          
ashnazg (ashnazg)          
bmajdak (bmajdak)          
brzuchal (brzuchal)          
bwoebi (bwoebi)          
crell (crell)          
derick (derick)          
dharman (dharman)           
duncan3dc (duncan3dc)          
galvao (galvao)          
jasny (jasny)          
kinncj (kinncj)          
levim (levim)          
marandall (marandall)          
nicolasgrekas (nicolasgrekas)          
ocramius (ocramius)          
ramsey (ramsey)          
reywob (reywob)          
sergey (sergey)          
svpernova09 (svpernova09)          
theodorejb (theodorejb)          
trowski (trowski)          
villfa (villfa)          
Final result: 9 0 1 0 0 1 9 0 3 0
This poll has been closed.
Straw poll: Favorite choice of namespace
Real name iterable_any() and iterable_all() iter\ iterable\ PHP\ PHP\iter\ PHP\iterable\ Ext\Spl\ Spl\ Spl\iter\ Spl\iterable\
alec (alec)          
as (as)          
ashnazg (ashnazg)          
bmajdak (bmajdak)          
brzuchal (brzuchal)          
bwoebi (bwoebi)          
crell (crell)          
derick (derick)          
dharman (dharman)           
duncan3dc (duncan3dc)          
galvao (galvao)          
jasny (jasny)          
kinncj (kinncj)          
levim (levim)          
marandall (marandall)          
nicolasgrekas (nicolasgrekas)          
ocramius (ocramius)          
ramsey (ramsey)          
reywob (reywob)          
sergey (sergey)          
svpernova09 (svpernova09)          
theodorejb (theodorejb)          
trowski (trowski)          
villfa (villfa)          
Final result: 9 0 1 0 0 1 9 0 3 0
This poll has been closed.
Straw poll: Second favorite choice of namespace
Real name iterable_any() and iterable_all() iter\ iterable\ PHP\ PHP\iter\ PHP\iterable\ Ext\Spl\ Spl\ Spl\iter\ Spl\iterable\
alec (alec)          
as (as)          
ashnazg (ashnazg)           
bmajdak (bmajdak)          
brzuchal (brzuchal)          
crell (crell)          
derick (derick)          
dharman (dharman)          
duncan3dc (duncan3dc)          
galvao (galvao)          
jasny (jasny)          
kinncj (kinncj)           
levim (levim)           
marandall (marandall)          
nicolasgrekas (nicolasgrekas)          
ocramius (ocramius)          
ramsey (ramsey)          
reywob (reywob)          
sergey (sergey)           
svpernova09 (svpernova09)          
theodorejb (theodorejb)          
trowski (trowski)          
villfa (villfa)          
Final result: 0 2 5 0 2 6 4 0 0 0
This poll has been closed.
Straw poll: Third favorite choice of namespace
Real name iterable_any() and iterable_all() iter\ iterable\ PHP\ PHP\iter\ PHP\iterable\ Ext\Spl\ Spl\ Spl\iter\ Spl\iterable\
as (as)          
ashnazg (ashnazg)          
crell (crell)          
dharman (dharman)          
duncan3dc (duncan3dc)           
galvao (galvao)          
jasny (jasny)          
kinncj (kinncj)          
marandall (marandall)          
ocramius (ocramius)           
ramsey (ramsey)           
sergey (sergey)          
svpernova09 (svpernova09)          
theodorejb (theodorejb)          
trowski (trowski)          
villfa (villfa)          
Final result: 10 0 2 0 0 0 0 0 0 1
This poll has been closed.
Straw poll: Fourth favorite choice of namespace
Real name iterable_any() and iterable_all() iter\ iterable\ PHP\ PHP\iter\ PHP\iterable\ Ext\Spl\ Spl\ Spl\iter\ Spl\iterable\
ashnazg (ashnazg)          
crell (crell)          
dharman (dharman)          
jasny (jasny)          
ocramius (ocramius)          
ramsey (ramsey)          
svpernova09 (svpernova09)          
Final result: 0 0 0 0 0 0 1 1 0 5
This poll has been closed.
Straw poll: Fifth favorite choice of namespace
Real name iterable_any() and iterable_all() iter\ iterable\ PHP\ PHP\iter\ PHP\iterable\ Ext\Spl\ Spl\ Spl\iter\ Spl\iterable\
ashnazg (ashnazg)          
crell (crell)          
dharman (dharman)          
jasny (jasny)          
Final result: 0 0 0 1 0 2 1 0 0 0
This poll has been closed.
Straw poll: Sixth favorite choice of namespace
Real name iterable_any() and iterable_all() iter\ iterable\ PHP\ PHP\iter\ PHP\iterable\ Ext\Spl\ Spl\ Spl\iter\ Spl\iterable\
ashnazg (ashnazg)          
jasny (jasny)           
Final result: 0 0 0 0 0 1 0 0 0 0
This poll has been closed.
Straw poll: Seventh favorite choice of namespace
Real name iterable_any() and iterable_all() iter\ iterable\ PHP\ PHP\iter\ PHP\iterable\ Ext\Spl\ Spl\ Spl\iter\ Spl\iterable\
ashnazg (ashnazg)          
jasny (jasny)          
Final result: 0 0 0 0 1 0 0 0 0 1
This poll has been closed.
Straw poll: Eighth favorite choice of namespace
Real name iterable_any() and iterable_all() iter\ iterable\ PHP\ PHP\iter\ PHP\iterable\ Ext\Spl\ Spl\ Spl\iter\ Spl\iterable\
ashnazg (ashnazg)          
jasny (jasny)          
Final result: 0 0 0 2 0 0 0 0 0 0
This poll has been closed.
Straw poll: Ninth favorite choice of namespace
Real name iterable_any() and iterable_all() iter\ iterable\ PHP\ PHP\iter\ PHP\iterable\ Ext\Spl\ Spl\ Spl\iter\ Spl\iterable\
ashnazg (ashnazg)          
jasny (jasny)          
Final result: 1 0 0 0 0 0 0 0 1 0
This poll has been closed.
Straw poll: Tenth favorite choice of namespace
Real name iterable_any() and iterable_all() iter\ iterable\ PHP\ PHP\iter\ PHP\iterable\ Ext\Spl\ Spl\ Spl\iter\ Spl\iterable\
ashnazg (ashnazg)          
jasny (jasny)          
Final result: 0 0 1 0 0 0 0 1 0 0
This poll has been closed.

What the functions do

See https://wiki.php.net/rfc/any_all_on_iterable

/** Determines whether any element of the iterable satisfies the predicate. */
function(iterable $input, ?callable $callback = null) {
    foreach ($input as $v) {
        if ($callback !== null ? $callback($v) : $v) {
            return true;
        }
    }
    return false;
};
 
/** Determines whether all elements of the iterable satisfy the predicate */
function(iterable $input, ?callable $callback = null) {
    foreach ($input as $v) {
        if (!($callback !== null ? $callback($v) : $v)) {
            return false;
        }
    }
    return true;
};

Rejected Choices

Using static methods instead of global functions was not considered since it would be impractical to polyfill new functions that get added in future php versions in a standard way. (e.g. IterUtils::all())

all() and iter_all()

Existing iterator methods

The prefix iterator_ was not considered. In PHP, Iterator and IteratorAggregate already exist, and classes that implement Traversable must implement either Iterator or IteratorAggregate. The name iterator_ would be misleading for functions that also accept arrays.

  • I don't want to be in a situation where there are a large number of iterator_*() functions, where some accept Traversable and some accept iterable.
  • I also don't want to be in a situation where some have $iterator as a named argument (since PHP 8.0, e.g. iterator_to_array()) and others have $iterable.
  • If I was choosing names from scratch, *foo(iterable $iterable, ...) would make more sense than iterator_foo(iterable $iterator, ...)

Changing other iterator functions such as iterator_apply(), iterator_count(), and iterator_to_array() to accept iterator instead of Traversable(Iterator and IteratorAggregate) is out of the scope of the RFC or straw poll.

  • My preference would be to add new iterable_apply(), iterable_count(), and iterable_to_array() functions instead of modifying the existing methods. This would be possible to polyfill, and it would be less likely that code developed for 8.1+ would pass arrays that would be rejected by php 8.0 and older.
  • Any alternative RFCs to change the behaviors of iterator_apply(), iterator_count(), and iterator_to_array() can be done independently of adding *any() and *all().

References

rfc/any_all_on_iterable_straw_poll_namespace.1610891472.txt.gz · Last modified: 2021/01/17 13:51 by tandre