Re: [VOTE] PHP\iterable\any() and all() on iterables
| From: | Levi Morrison via internals | Date: | Tue, 09 Feb 2021 00:48:32 +0000 |
| Subject: | Re: [VOTE] PHP\iterable\any() and all() on iterables | ||
| References: | 1 2 3 4 5 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-113122@lists.php.net to get a copy of this message | ||
On Mon, Feb 8, 2021 at 5:15 PM tyson andre <tysonandre775@hotmail.com> wrote:
>
> Hi Larry Garfield,
>
> > > Hi Larry Garfield,
> > >
> > > > > Hi internals,
> > > > >
> > > > > Voting has started on
> > > > > https://wiki.php.net/rfc/any_all_on_iterable and
> > > > > ends on 2021-02-22.
> > > > >
> > > > > This RFC proposes to add the functions `PHP\iterable\any(iterable
> > > > > $input, ?callable $callback = null): bool
and
> > > > > PHP\iterable\all(...)`
> > > > > to PHP's standard library's function set, using the namespace
> > > > > preferred
> > > > > in the previous straw poll.
> > > > >
> > > > > There is a primary vote on whether to add the functions, and a
> > > > > secondary vote on the name to use within the
> > > > > PHP\iterable namespace.
> > > > >
> > > > > Thanks,
> > > > > - Tyson
> > > > > --
> > > > > PHP Internals - PHP Runtime Development Mailing List
> > > > > To unsubscribe, visit:
> > > > > https://www.php.net/unsub.php
> > > >
> > > >
> > > > Ak! I literally just finished reading it and wanted to note a lack of clarity
> > > > on one point. :-)
> > > >
> > > > The signature of the callback is never specified explicitly. The ternary is a
> > > > bit confusing. I assume the signature is
> > > >
> > > > callable(mixed): bool
> > > >
> > > > But that's not made explicit. It's also not made explict that
> > > > omitting the callable collapses to "is truthy". That's a sensible thing to do, but
> > > > it's not stated explicitly anywhere, just inferred from the code sample.
> > > >
> > > > I'm not sure if it's safe to clarify at this point as the vote just
> > > > started.
> > >
> > > If there is a callable, it allows callable(mixed):
> > > mixed,
> > > and converts the callable's return value to a boolean.
> > > So omitting the callable is the same as passing in the callable `fn($x)
> > > => $x, which is equivalent to fn($x) =>
> > > (bool)$x`.
> > > This is exactly what the reference implementation would do.
> > >
> > > I definitely should have clarified it instead of assuming that the
> > > reference implementation was clear enough.
> > >
> > > I clarified this and gave examples because the RFC started a few hours
> > > ago and the implementation didn't change.
> >
> > Oof. I'm glad I asked, because I don't like that at all. If available, the
> > callable should be returning bool, not "anything that may be truthy/falsy." If you have
> > an explicit function, it should have an explicit return type. A truthy check is a reasonable
> > default, but not for when you're opting in to specifying the logic.
> >
> > I am in favor of the RFC, but I will have to consider if that changes my vote to No.
> >
> > --Larry Garfield
>
> This was a deliberate choice and is consistent with the weak type comparison behavior of
> array_filter() and other functions that default to using weak type checks internally.
>
> I'd agree that I'd prefer to see callbacks returning booleans in code I'm
> reviewing,
> but a truthiness check seems more practical and consistent with the rest of the language
> than throwing a TypeError or checking the predicate return value using !==
> true
>
> This was made to make PHP more widely accessible and free of surprises.
> e.g. (bool)array_filter($arr, $predicate) can be safely
> converted to any($arr, $predicate) without introducing a TypeError
> or behavior change.
>
> ```
> php > var_dump(array_filter([-1,0,1], fn($x)=>$x));
> array(2) {
> [0]=>
> int(-1)
> [2]=>
> int(1)
> }
> ```
>
> This is the same choice as many other dynamic languages that aren't compiled ahead of time
> have made.
>
> ```
> # python
> >>> any([1])
> True
> >>> any([0])
> False
> # Ruby
> irb(main):001:0> [nil].any?
> => false
> irb(main):002:0> [false].any?
> => false
> irb(main):003:0> !!0
> => true
> irb(main):004:0> [0].any?
> => true
> # JavaScript
> > [0].some(x=>x)
> false
> > [1].some(x=>x)
> true
> ```
>
> It is currently possible to check if code is passing a callable returning anything other than a
> boolean
> to functions such as array_filter() using a wide variety of
> static analyzers/tools, e.g. http://github.com/phan/phan
>
> ```
> <?php
> // Phan emits "PhanTypeMismatchArgumentInternal Argument 2 ($callback) is (fn) of type
> Closure(int):int
> // but \array_filter() takes callable(mixed):bool|callable(mixed,mixed):bool"
> array_filter([1], fn (int $x): int => $x % 3);
> ```
>
> Thanks,
> -Tyson
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>
For what it is worth, in C++ it is fairly normal to use a convertible
to bool type. For instance, having an overload on a < b for iterators
can return whatever type it wants, as long as it is contextually
convertible to bool.