Countable Type Hint

php.internals

Craig Duncan (PHP)

9 years ago
Hi everybody Following on from the recent rfc for *count()* ( https://wiki.php.net/rfc/counting_non_countables) and the one for *iterable* (https://wiki.php.net/rfc/iterable) it would be useful if there was a `countable` type hint: function foo(countable $thing) { if (count($thing) > 0) { # ... } } However I think this it is much more useful when combined with *iterable*, maybe something like (arraylike = iterable && countable) function handle_records(arraylike $result) { if (count($result) === 0) { handle_empty(); return; } foreach ($result as $value) { handle_value($value); } } Does anybody have any thoughts on this? Should I bring *countable* to RFC? Should I bring *arraylike* to RFC? Thanks, Craig

Levi Morrison

9 years ago
On Thu, Nov 17, 2016 at 5:52 AM, Craig Duncan <php@duncanc.co.uk> wrote:
> Hi everybody > > Following on from the recent rfc for *count()* ( > https://wiki.php.net/rfc/counting_non_countables) and the one for *iterable* > (https://wiki.php.net/rfc/iterable) it would be useful if there was a > `countable` type hint: > > function foo(countable $thing) > { > if (count($thing) > 0) { > # ... > } > } > > However I think this it is much more useful when combined with *iterable*, > maybe something like (arraylike = iterable && countable) > > function handle_records(arraylike $result) > { > if (count($result) === 0) { > handle_empty(); > return; > } > > foreach ($result as $value) { > handle_value($value); > } > } > > Does anybody have any thoughts on this? > Should I bring *countable* to RFC? > Should I bring *arraylike* to RFC? > > Thanks, > Craig
It's definitely not doable with the name `countable`. Class/Trait/Interface names are case insensitive. This means `countable` already has meaning and it is unambiguously the interface.

Josh Di Fabio

9 years ago
On Thu, Nov 17, 2016 at 1:00 PM Levi Morrison <levim@php.net> wrote:
> On Thu, Nov 17, 2016 at 5:52 AM, Craig Duncan <php@duncanc.co.uk> wrote: > > Hi everybody > > > > Following on from the recent rfc for *count()* ( > > https://wiki.php.net/rfc/counting_non_countables) and the one for > *iterable* > > (https://wiki.php.net/rfc/iterable) it would be useful if there was a > > `countable` type hint: > > > > function foo(countable $thing) > > { > > if (count($thing) > 0) { > > # ... > > } > > } > > > > However I think this it is much more useful when combined with > *iterable*, > > maybe something like (arraylike = iterable && countable) > > > > function handle_records(arraylike $result) > > { > > if (count($result) === 0) { > > handle_empty(); > > return; > > } > > > > foreach ($result as $value) { > > handle_value($value); > > } > > } > > > > Does anybody have any thoughts on this? > > Should I bring *countable* to RFC? > > Should I bring *arraylike* to RFC? > > > > Thanks, > > Craig > > It's definitely not doable with the name `countable`. > Class/Trait/Interface names are case insensitive. This means > `countable` already has meaning and it is unambiguously the interface. > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php
What's the benefit of such an interface? Why not simply ask for `int $count` in your param list instead?

Craig Duncan (PHP)

9 years ago
On 17 November 2016 at 13:50, Josh Di Fabio <joshdifabio@gmail.com> wrote:
> What's the benefit of such an interface? Why not simply ask for `int > $count` in your param list instead? >
Using the example from my original email, it's a bit awkward to always have to pass the count of a countable: handle_records($result, count($result)); The number of items in a countable can be established from the countable, asking for it as a additional parameter doesn't make much sense to me

Josh Di Fabio

9 years ago
On Thu, Nov 17, 2016 at 2:01 PM Craig Duncan <php@duncanc.co.uk> wrote:
> On 17 November 2016 at 13:50, Josh Di Fabio <joshdifabio@gmail.com> wrote: > > What's the benefit of such an interface? Why not simply ask for `int > $count` in your param list instead? > > > Using the example from my original email, it's a bit awkward to always > have to pass the count of a countable: > handle_records($result, count($result)); > > The number of items in a countable can be established from the countable, > asking for it as a additional parameter doesn't make much sense to me > >
Apologies, I thought you were simply proposing the following: interface Countable { function count(): int; } But you're actually proposing the following as well? interface Arraylike extends Iterator, Countable { } I can see the use of an interface which combines Iterator and Countable, but not Countable on its own.

Christoph Becker

9 years ago
On 17.11.2016 at 15:06, Josh Di Fabio wrote:
> Apologies, I thought you were simply proposing the following: > > interface Countable > { > function count(): int; > }
We already have this as of PHP 5.1.0, see <http://php.net/manual/en/class.countable.php>. :-)
-- Christoph M. Becker

Rowan Collins

9 years ago
On 17/11/2016 14:06, Josh Di Fabio wrote:
> Apologies, I thought you were simply proposing the following: > > interface Countable > { > function count(): int; > }
No, what Craig is proposing is a type hint that covers both the existing Countable interface and primitives which are naturally countable. If the union types RFC had passed, you'd be able to say "array|Traversable $foo"; a recent RFC lets you instead say "iterable $foo". The suggestion is to add a keyword which similarly acts as "array|Countable $foo". Unfortunately, as others have pointed out, it can't be called just "countable", because that's the name of the existing interface. The principle seems sound though, assuming we don't want to go down the route of treating arrays as implementing interfaces. Regards,
-- Rowan Collins [IMSoP]

Niklas Keller

9 years ago
> > No, what Craig is proposing is a type hint that covers both the existing > Countable interface and primitives which are naturally countable. > > If the union types RFC had passed, you'd be able to say "array|Traversable > $foo"; a recent RFC lets you instead say "iterable $foo". The suggestion is > to add a keyword which similarly acts as "array|Countable $foo". > > Unfortunately, as others have pointed out, it can't be called just > "countable", because that's the name of the existing interface. The > principle seems sound though, assuming we don't want to go down the route > of treating arrays as implementing interfaces. >
I think it's better to implement method calls on primitives than introducing new type keywords for every edge-case now. Once we have methods on primitives (counting array here as primitive), arrays can just implement the Countable interface and we're fine using Countable (the interface). Methods on primitives have the additional advantage that we can clean up the API and have improved readability when chaining e.g. array methods like filter and map. Regards, Niklas

Larry Garfield

9 years ago
On 11/17/2016 10:12 AM, Niklas Keller wrote:
>> No, what Craig is proposing is a type hint that covers both the existing >> Countable interface and primitives which are naturally countable. >> >> If the union types RFC had passed, you'd be able to say "array|Traversable >> $foo"; a recent RFC lets you instead say "iterable $foo". The suggestion is >> to add a keyword which similarly acts as "array|Countable $foo". >> >> Unfortunately, as others have pointed out, it can't be called just >> "countable", because that's the name of the existing interface. The >> principle seems sound though, assuming we don't want to go down the route >> of treating arrays as implementing interfaces. >> > I think it's better to implement method calls on primitives than > introducing new type keywords for every edge-case now. Once we have methods > on primitives (counting array here as primitive), arrays can just implement > the Countable interface and we're fine using Countable (the interface). > > Methods on primitives have the additional advantage that we can clean up > the API and have improved readability when chaining e.g. array methods like > filter and map. > > Regards, Niklas
Methods on primitives has been proposed a few times, but never gone anywhere because it's, well, really hard to do. :-) Have you a recommendation for how to do so? (Honest question; I'd love primitive methods, especially if they're user-extensible.) --Larry Garfield

Niklas Keller

9 years ago
2016-11-19 19:18 GMT+01:00 Larry Garfield <larry@garfieldtech.com>:
> On 11/17/2016 10:12 AM, Niklas Keller wrote: > >> No, what Craig is proposing is a type hint that covers both the existing >>> Countable interface and primitives which are naturally countable. >>> >>> If the union types RFC had passed, you'd be able to say >>> "array|Traversable >>> $foo"; a recent RFC lets you instead say "iterable $foo". The suggestion >>> is >>> to add a keyword which similarly acts as "array|Countable $foo". >>> >>> Unfortunately, as others have pointed out, it can't be called just >>> "countable", because that's the name of the existing interface. The >>> principle seems sound though, assuming we don't want to go down the route >>> of treating arrays as implementing interfaces. >>> >>> I think it's better to implement method calls on primitives than >> introducing new type keywords for every edge-case now. Once we have >> methods >> on primitives (counting array here as primitive), arrays can just >> implement >> the Countable interface and we're fine using Countable (the interface). >> >> Methods on primitives have the additional advantage that we can clean up >> the API and have improved readability when chaining e.g. array methods >> like >> filter and map. >> >> Regards, Niklas >> > > > Methods on primitives has been proposed a few times, but never gone > anywhere because it's, well, really hard to do. :-) Have you a > recommendation for how to do so
What's the hard part about it? It's already possible with an extension: https://github.com/nikic/scalar_objects
> (Honest question; I'd love primitive methods, especially if they're > user-extensible.)
I don't know whether they should be user-extensible, probably not. It prevents adding new built-in methods because of BC concerns. It might lead to conflicting definitions in fundamental primitive operations (yes, compare that with mbstring.func_overload). Also have a look at the JS world and extending Object and Array. Regards, Niklas

Jordi Boggiano

9 years ago
On 17/11/2016 13:52, Craig Duncan wrote:
> Hi everybody > > Following on from the recent rfc for *count()* ( > https://wiki.php.net/rfc/counting_non_countables) and the one for *iterable* > (https://wiki.php.net/rfc/iterable) it would be useful if there was a > `countable` type hint: > > function foo(countable $thing) > { > if (count($thing) > 0) { > # ... > } > } > > However I think this it is much more useful when combined with *iterable*, > maybe something like (arraylike = iterable && countable) > > function handle_records(arraylike $result) > { > if (count($result) === 0) { > handle_empty(); > return; > } > > foreach ($result as $value) { > handle_value($value); > } > } > > Does anybody have any thoughts on this? > Should I bring *countable* to RFC? > Should I bring *arraylike* to RFC?
IMO if we add an arraylike-style hint it should include ArrayAccess as well, and array_* functions should probably be fixed to work with arraylike objects too, then it'd bring actual value. Cheers
-- Jordi Boggiano @seldaek - http://seld.be

Stas Malyshev

9 years ago
Hi!
> Does anybody have any thoughts on this? > Should I bring *countable* to RFC? > Should I bring *arraylike* to RFC?
Nothing prevents one from having such interfaces or classes or traits if they need it. I don't see any need of adding more special cases into the language. Special cases are always bad design and we shouldn't make it worse.
-- Stas Malyshev smalyshev@gmail.com

Craig Duncan (PHP)

9 years ago
On 19 November 2016 at 18:36, Stanislav Malyshev <smalyshev@gmail.com> wrote:
> > > Should I bring *countable* to RFC? > > Nothing prevents one from having such interfaces or classes or traits if > they need it. I don't see any need of adding more special cases into the > language. Special cases are always bad design and we shouldn't make it > worse. >
Nothing prevents it? As far as I'm aware there's no current way to type hint Countable or array. How would one add an interface that includes Countable and arrays?

Stas Malyshev

9 years ago
Hi!
> Nothing prevents it? As far as I'm aware there's no current way to type > hint Countable or array.
No, there's not - as there's no way to make other complex type conditions as type. You still can check for it, or just use count().
> How would one add an interface that includes Countable and arrays?
You can not add interface that includes multiple types. Neither should you, that's not what interfaces are for. Inventing one-off complex type expressions for one-off cases just makes language more complex and less consistent. It's not a good direction to develop, and it serves very narrow use case which can easily be served by simple code.
-- Stas Malyshev smalyshev@gmail.com

Daniel Morris

9 years ago
If somehow the Countable type-hint can absorb primitives, another example I would like to see with similar behaviour is Serializable, the type-hint currently allows classes implementing the Serializable interface to be serialized, but primitives (which are serializeable) can not be serialized when passed to the same method or function. I'm sure there are more edge-cases like this also...
-- Daniel Morris daniel@honestempire.com