Hi!
A few weeks ago I resurrected a two year old proposal for adding two array
functions, namely array_every() and array_some(), modelled after their
JavaScript equivalent.
https://github.com/php/php-src/pull/1385
The most notable comment was that it would be nice to support Traversable
as well as arrays; instead of only supporting this for my own functions,
I've generalised this so that other functions can take advantage of this as
well. These are the additions:
-
A ZPP argument; the "t" (for traversable) argument type has been added
that checks for either an array or implementation of zend_ce_traversable. -
A generic iteration function, called php_traverse(); it accepts:
a. the zval* to iterate over,
b. a step-wise function that receives the value and key, and returns a
boolean that determines whether iteration should continue or not,
c. a traversal mode (only values, or keys and values),
d. a context that's sent to the step-wise function. -
A concrete implementation of a step-wise iteration function,
php_traverse_until, that gets called as part of array_every() and
array_some().
The implementation of above proposal can be found in the PR itself. With
more functions adopting this idea, you could see this work:
var_dump(array_reduce((function() {
yield 1;
yield 2;
yield 3;
})(), function($total, $current) {
return $total + $current;
}, 0); // int(6)
Let me know what you think!
Hi!
A few weeks ago I resurrected a two year old proposal for adding two array
functions, namely array_every() and array_some(), modelled after their
JavaScript equivalent.https://github.com/php/php-src/pull/1385
...
Let me know what you think!
Sounds awesome!
--
Regards,
Mike
Hi,
The most notable comment was that it would be nice to support Traversable
as well as arrays; instead of only supporting this for my own functions,
I've generalised this so that other functions can take advantage of this as
well. These are the additions:
A ZPP argument; the "t" (for traversable) argument type has been added
that checks for either an array or implementation of zend_ce_traversable.A generic iteration function, called php_traverse(); it accepts:
a. the zval* to iterate over,
b. a step-wise function that receives the value and key, and returns a
boolean that determines whether iteration should continue or not,
c. a traversal mode (only values, or keys and values),
d. a context that's sent to the step-wise function.
I really like this concept to unify by access pattern, hiding the actual
implementation!
- A concrete implementation of a step-wise iteration function,
php_traverse_until, that gets called as part of array_every() and
array_some().
I wonder if we can find a better naming scheme. For some array_
functions this will work, others not. This again feeds the "PHP is so
inconsistent"-trolls. At the moment I'm leaning towards simply using
every() and some_of() without reference to a type. Or maybe introduce,
to restart the namespace-debate, php\every(), php\search(), php
\someOf(), php\product(), etc. and deprecate array_search()
etc.
johannes
On Wed, Jul 15, 2015 at 3:43 PM, Johannes Schlüter johannes@schlueters.de
wrote:
Hi,
The most notable comment was that it would be nice to support Traversable
as well as arrays; instead of only supporting this for my own functions,
I've generalised this so that other functions can take advantage of this
as
well. These are the additions:
A ZPP argument; the "t" (for traversable) argument type has been added
that checks for either an array or implementation of zend_ce_traversable.A generic iteration function, called php_traverse(); it accepts:
a. the zval* to iterate over,
b. a step-wise function that receives the value and key, and returns a
boolean that determines whether iteration should continue or not,
c. a traversal mode (only values, or keys and values),
d. a context that's sent to the step-wise function.I really like this concept to unify by access pattern, hiding the actual
implementation!
- A concrete implementation of a step-wise iteration function,
php_traverse_until, that gets called as part of array_every() and
array_some().I wonder if we can find a better naming scheme. For some array_
functions this will work, others not. This again feeds the "PHP is so
inconsistent"-trolls. At the moment I'm leaning towards simply using
every() and some_of() without reference to a type. Or maybe introduce,
to restart the namespace-debate, php\every(), php\search(), php
\someOf(), php\product(), etc. and deprecatearray_search()
etc.johannes
Nikic designed "Iter" some time ago, when he finished adding Generators to
PHP.
Perhaps some ideas could be taken from it.
https://github.com/nikic/iter
I suggest writing an RFC and target 8.0, while the deprecations could
target 7.X
Also, there has been an open subject for ages about how could we uniform
array and Traversable internally, as well as from PHP user land (the main
subject was then to add support for ArrayAccess to every array_***() PHP
function).
I'm happy this bumps the subject up , as it is quite a hot topic.
Julien Pauli
On Wed, Jul 15, 2015 at 3:43 PM, Johannes Schlüter johannes@schlueters.de
wrote:Hi,
The most notable comment was that it would be nice to support Traversable
as well as arrays; instead of only supporting this for my own functions,
I've generalised this so that other functions can take advantage of this
as
well. These are the additions:
A ZPP argument; the "t" (for traversable) argument type has been added
that checks for either an array or implementation of zend_ce_traversable.A generic iteration function, called php_traverse(); it accepts:
a. the zval* to iterate over,
b. a step-wise function that receives the value and key, and returns a
boolean that determines whether iteration should continue or not,
c. a traversal mode (only values, or keys and values),
d. a context that's sent to the step-wise function.I really like this concept to unify by access pattern, hiding the actual
implementation!
- A concrete implementation of a step-wise iteration function,
php_traverse_until, that gets called as part of array_every() and
array_some().I wonder if we can find a better naming scheme. For some array_
functions this will work, others not. This again feeds the "PHP is so
inconsistent"-trolls. At the moment I'm leaning towards simply using
every() and some_of() without reference to a type. Or maybe introduce,
to restart the namespace-debate, php\every(), php\search(), php
\someOf(), php\product(), etc. and deprecatearray_search()
etc.johannes
Nikic designed "Iter" some time ago, when he finished adding Generators to
PHP.
Perhaps some ideas could be taken from it.
https://github.com/nikic/iterI suggest writing an RFC and target 8.0, while the deprecations could
target 7.XAlso, there has been an open subject for ages about how could we uniform
array and Traversable internally, as well as from PHP user land (the main
subject was then to add support for ArrayAccess to every array_***() PHP
function).I'm happy this bumps the subject up , as it is quite a hot topic.
Do note that the union types RFC would also alleviate some of this
pain for user-land functions, since array | Traversable
would cover
the required access pattern. I think this is a superior approach
myself, but I may be a bit biased as I am authoring that proposal:
https://wiki.php.net/rfc/union_types
Do note that the union types RFC would also alleviate some of this
pain for user-land functions, sincearray | Traversable
would cover
the required access pattern. I think this is a superior approach
myself, but I may be a bit biased as I am authoring that proposal:
https://wiki.php.net/rfc/union_types
I like the idea of union types in general, but have always felt that a typehint of Traversable should accept arrays as a matter of course. The only thing such a typehint guarantees is that foreach will work (there are no methods defined that can be called directly), and an array meets that condition. The only difference I can see is in the passing / mutability behaviour of objects vs non-objects.
Regards,
Rowan Collins
[IMSoP]
On Wed, Jul 15, 2015 at 9:53 PM, Rowan Collins rowan.collins@gmail.com
wrote:
Do note that the union types RFC would also alleviate some of this
pain for user-land functions, sincearray | Traversable
would cover
the required access pattern. I think this is a superior approach
myself, but I may be a bit biased as I am authoring that proposal:
https://wiki.php.net/rfc/union_typesI like the idea of union types in general, but have always felt that a
typehint of Traversable should accept arrays as a matter of course. The
only thing such a typehint guarantees is that foreach will work (there are
no methods defined that can be called directly), and an array meets that
condition. The only difference I can see is in the passing / mutability
behaviour of objects vs non-objects.
But instanceof and anything related to Reflection or get_class or relevant
code will fail on array.
Regards,
Rowan Collins
[IMSoP]
Benjamin Eberlei wrote on 15/07/2015 21:19:
On Wed, Jul 15, 2015 at 9:53 PM, Rowan Collins
<rowan.collins@gmail.com mailto:rowan.collins@gmail.com> wrote:On 15 July 2015 20:39:05 GMT+01:00, Levi Morrison <levim@php.net <mailto:levim@php.net>> wrote: >Do note that the union types RFC would also alleviate some of this >pain for user-land functions, since `array | Traversable` would cover >the required access pattern. I think this is a superior approach >myself, but I may be a bit biased as I am authoring that proposal: >https://wiki.php.net/rfc/union_types I like the idea of union types in general, but have always felt that a typehint of Traversable should accept arrays as a matter of course. The only thing such a typehint guarantees is that foreach will work (there are no methods defined that can be called directly), and an array meets that condition. The only difference I can see is in the passing / mutability behaviour of objects vs non-objects.
But instanceof and anything related to Reflection or get_class or
relevant code will fail on array.
Ah, yes, I hadn't thought of reflection type things. I don't think
instanceof would be a problem, because checking for any class or
interface other than Traversable would correctly return false; not sure
if it would make sense for "array() instanceof Traversable" to return
true or not...
Benjamin Eberlei wrote on 15/07/2015 21:19:
But instanceof and anything related to Reflection or get_class or
relevant code will fail on array.Ah, yes, I hadn't thought of reflection type things. I don't think
instanceof would be a problem, because checking for any class or
interface other than Traversable would correctly return false; not sure
if it would make sense for "array() instanceof Traversable" to return
true or not...
Maybe some pseudotype like callable (e.g. iteratable) makes more sense then?
--
Regards,
Mike
Hi!
Benjamin Eberlei wrote on 15/07/2015 21:19:
But instanceof and anything related to Reflection or get_class or
relevant code will fail on array.Ah, yes, I hadn't thought of reflection type things. I don't think
instanceof would be a problem, because checking for any class or
interface other than Traversable would correctly return false; not sure
if it would make sense for "array() instanceof Traversable" to return
true or not...Maybe some pseudotype like callable (e.g. iteratable) makes more sense
then?
I'm okay with a pseudo type.
My opinion on the matter at this point is such that I care more about
providing an API of sorts to support both kinds of structures, so that any
developer can write an extension that can leverage this capability and
make this available in user-land.
Having array_some() and array_every() support this doesn't have to be
documented for all I care, if anything it serves as an example of what can
be done.
The most immediate feedback I would like is:
a) whether it's useful to add as an API,
b) a review of the code in php_traversal.[ch]
--
Regards,
Mike
Benjamin Eberlei wrote on 15/07/2015 21:19:
But instanceof and anything related to Reflection or get_class or
relevant code will fail on array.Ah, yes, I hadn't thought of reflection type things. I don't think
instanceof would be a problem, because checking for any class or
interface other than Traversable would correctly return false; not sure
if it would make sense for "array() instanceof Traversable" to return
true or not...Maybe some pseudotype like callable (e.g. iteratable) makes more sense then?
People have talked about creating types like so:
type Iterable = array | Traversable;
which could then be used as normal:
function foo(Iterable $f);
I understand that this is the second feature I have mentioned in this
train of thought that has not yet be officially proposed, but I think
it's relevant. Why special case a pseudo-type if we can have a generic
way of making them in user-land?
Levi Morrison wrote on 16/07/2015 16:23:
People have talked about creating types like so:
type Iterable = array | Traversable;
which could then be used as normal:
function foo(Iterable $f);
I kind of like this idea.
Why special case a pseudo-type if we can have a generic
way of making them in user-land?
Well, for the same reason as large amounts of the core library exist
(and PHP's is small compared to some): standardisation and ease of use.
I think "array | Traversable" is a common enough use-case that it
deserves a built-in name, even if a userland naming system is available.
Regards,
Rowan Collins
[IMSoP]
Levi Morrison wrote on 16/07/2015 16:23:
People have talked about creating types like so:
type Iterable = array | Traversable;
which could then be used as normal:
function foo(Iterable $f);
I kind of like this idea.
Why special case a pseudo-type if we can have a generic
way of making them in user-land?Well, for the same reason as large amounts of the core library exist (and
PHP's is small compared to some): standardisation and ease of use. I think
"array | Traversable" is a common enough use-case that it deserves a
built-in name, even if a userland naming system is available.
I assume if type Iterable = array | Traversable
can be built in
user-land then it will be done using the same mechanisms in core
(meaning it wouldn't be a special case or one-off type).