Re: [VOTE] PHP\iterable\any() and all() on iterables

From: Date: Tue, 09 Feb 2021 00:15:18 +0000
Subject: Re: [VOTE] PHP\iterable\any() and all() on iterables
References: 1 2 3 4  Groups: php.internals 
Request: Send a blank email to internals+get-113120@lists.php.net to get a copy of this message
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

« previous php.internals (#113120) next »