[RFC] Mixed type

php.internals

Dan Ackroyd

6 years ago
Hi Internals, Here is an RFC for adding a 'mixed' type to the language: https://wiki.php.net/rfc/mixed_type_v2 The RFC builds on an earlier draft by Michael Moravec. Part of the motivation for pursuing this RFC was my recent experience in upgrading an application to PHP 7.4. Being able to add types to the application made the code much easier to reason about, but there were places where I couldn't add type info due to the lack of mixed. That made it hard to see if that piece of code had been upgraded (but type info couldn't be added), or if that code still needed to be upgraded. cheers Dan Ack

Larry Garfield

6 years ago
On Mon, Apr 20, 2020, at 6:17 AM, Dan Ackroyd wrote:
> Hi Internals, > > Here is an RFC for adding a 'mixed' type to the language: > https://wiki.php.net/rfc/mixed_type_v2 > The RFC builds on an earlier draft by Michael Moravec. > > Part of the motivation for pursuing this RFC was my recent experience > in upgrading an application to PHP 7.4. > > Being able to add types to the application made the code much easier > to reason about, but there were places where I couldn't add type info > due to the lack of mixed. That made it hard to see if that piece of > code had been upgraded (but type info couldn't be added), or if that > code still needed to be upgraded. > > cheers > Dan > Ack
I am not against this, but now that we have Union types what places are there where the currently available type declarations are insufficient? Resource seems like the only remaining gap where you'd be forced to use `mixed` instead of a union. --Larry Garfield

Sara Golemon

6 years ago
On Mon, Apr 20, 2020 at 8:52 AM Larry Garfield <larry@garfieldtech.com> wrote:
> On Mon, Apr 20, 2020, at 6:17 AM, Dan Ackroyd wrote: > > Here is an RFC for adding a 'mixed' type to the language: > > https://wiki.php.net/rfc/mixed_type_v2 > > > > I am not against this, but now that we have Union types what places are > there where the currently available type declarations are insufficient? > Resource seems like the only remaining gap where you'd be forced to use > `mixed` instead of a union. > > I imagine some type combinations get pretty wide. Like, this is verbose AF.
null|bool|int|float|string|array|object|resource For the long term good of the language I'd prefer type aliases (or typedefs or usings or whatever you want to call them. use mixed = null|bool|int|float|string|array|object|resource; use scalar = null|bool|int|float|string; use number = int|float; That said, baking 'mixed' in as an implicit alias of the above isn't problematic for that future. -Sara

Larry Garfield

6 years ago
On Mon, Apr 20, 2020, at 9:15 AM, Sara Golemon wrote:
> On Mon, Apr 20, 2020 at 8:52 AM Larry Garfield <larry@garfieldtech.com> > wrote: > > > On Mon, Apr 20, 2020, at 6:17 AM, Dan Ackroyd wrote: > > > Here is an RFC for adding a 'mixed' type to the language: > > > https://wiki.php.net/rfc/mixed_type_v2 > > > > > > > I am not against this, but now that we have Union types what places are > > there where the currently available type declarations are insufficient? > > Resource seems like the only remaining gap where you'd be forced to use > > `mixed` instead of a union. > > > > I imagine some type combinations get pretty wide. Like, this is verbose AF. > > null|bool|int|float|string|array|object|resource
Sure, but how often is that an actual description of what the code accepts? I... cannot actually envision what code would actually accept that mess. :-) With union types and stringable already on the way, I'm not sure what other non-hypothetical use cases would still be that fugly that you'd now need to fall back to `mixed`. (I still think intersection types are needed, but that's a separate matter.) There may be, but I cannot think of them.
> For the long term good of the language I'd prefer type aliases (or typedefs > or usings or whatever you want to call them. > > use mixed = null|bool|int|float|string|array|object|resource; > use scalar = null|bool|int|float|string; > use number = int|float;
Concur.
> That said, baking 'mixed' in as an implicit alias of the above isn't > problematic for that future. > > -Sara
Concur. --Larry Garfield

Benjamin Eberlei

6 years ago
On Mon, Apr 20, 2020 at 5:17 PM Larry Garfield <larry@garfieldtech.com> wrote:
> On Mon, Apr 20, 2020, at 9:15 AM, Sara Golemon wrote: > > On Mon, Apr 20, 2020 at 8:52 AM Larry Garfield <larry@garfieldtech.com> > > wrote: > > > > > On Mon, Apr 20, 2020, at 6:17 AM, Dan Ackroyd wrote: > > > > Here is an RFC for adding a 'mixed' type to the language: > > > > https://wiki.php.net/rfc/mixed_type_v2 > > > > > > > > > > I am not against this, but now that we have Union types what places are > > > there where the currently available type declarations are insufficient? > > > Resource seems like the only remaining gap where you'd be forced to use > > > `mixed` instead of a union. > > > > > > I imagine some type combinations get pretty wide. Like, this is > verbose AF. > > > > null|bool|int|float|string|array|object|resource > > Sure, but how often is that an actual description of what the code > accepts? I... cannot actually envision what code would actually accept > that mess. :-) >
I can think of quite a few: - var_dump, print_r, more generally debugging/logging functions and wrappers thereof - json_encode, serialize, and more generally serialization and encoding functions, as return value as well for the inverse operations - database/nosql related functions (bindParam, bindValue) and as return value from generic functions like fetch() - Xpath::evaluate - ldap query functions And wrappers of these extensions could benefit from passing on the mixed type explicitly.

Markus Fischer

6 years ago
Hi, just picking on one of the examples: On 20.04.20 17:45, Benjamin Eberlei wrote:
> - json_encode, serialize, and more generally serialization and encoding > functions, as return value as well for the inverse operations
But how would this work for serializing resources, which is part of mixed? Seems to me exactly this case would benefit from a, albeit long though more accurate, actual union type. Hope that makes sense, - Markus

Máté Kocsis

6 years ago
> > But how would this work for serializing resources, which is part of mixed? >
https://3v4l.org/n9D2S The point is that many internal functions accept all types (including resources), even though they might not do much useful with some of them. Besides the functions that Benjamin mentioned, I'd add the *printf family that accept "mixed" parameters to the list. Seems to me exactly this case would benefit from a, albeit long though
> more accurate, actual union type.
Regarding accuracy, I believe the more types you have in an union type, the less important exact accuracy is, at least for return types and properties. For example if a function has a return type of mixed, I don't consider it a big deal if the implementation doesn't actually return 1 type (e.g. resource, null) in practice. Máté

Larry Garfield

6 years ago
On Mon, Apr 20, 2020, at 10:45 AM, Benjamin Eberlei wrote:
> > Sure, but how often is that an actual description of what the code > > accepts? I... cannot actually envision what code would actually accept > > that mess. :-) > > > > I can think of quite a few: > > - var_dump, print_r, more generally debugging/logging functions and > wrappers thereof > - json_encode, serialize, and more generally serialization and encoding > functions, as return value as well for the inverse operations > - database/nosql related functions (bindParam, bindValue) and as return > value from generic functions like fetch() > - Xpath::evaluate > - ldap query functions > > And wrappers of these extensions could benefit from passing on the mixed > type explicitly.
Valid examples. It would be helpful to add those to the RFC for clarity. --Larry Garfield

Máté Kocsis

6 years ago
Hi Larry,
> Sure, but how often is that an actual description of what the code > accepts? I... cannot actually envision what code would actually accept > that mess. :-) >
For example the recently added get_debug_type() function does, along with dozens of internal functions. Besides messy code, I'm sure that there are legitimate use-cases for the mixed type in user-land as well. use mixed = null|bool|int|float|string|array|object|resource;
> use scalar = null|bool|int|float|string; > use number = int|float;
I'm really not a fan of type aliases (at least user-land ones), but I also agree with Sara that these 3 "global" aliases would come handy. Actually, I was considering to also propose "scalar" and "number" in a later RFC. Cheers, Máté

Guilliam Xavier

6 years ago
On Mon, Apr 20, 2020 at 5:17 PM Larry Garfield <larry@garfieldtech.com> wrote:
> > With union types and stringable already on the way, I'm not sure what other non-hypothetical use cases would still be that fugly that you'd now need to fall back to `mixed`.
For instance: - the parameter of [a wrapper around] gettype() or an is_* function - the return of [a generic implementation of] ArrayAccess::offsetGet() or Iterator::current(), or of a userland array_value_first() or array_value_last() function To me, especially the return type declaration can be useful to ensure that [every code path of] the implementation returns a value.
-- Guilliam Xavier

Albert Casademont Filella

6 years ago
As Larry was asking for an example. The ParameterBag::get() function from Symfony (and others) that allows you to fetch request params, for example. That's a mixed type that could return different values, depending on your request body. Yes, I can type for all possible scalar values + null + array, but that's a bit of a PITA and phpstan would complain nonetheless, as the return type of theParameterBag ::get() function is "mixed" and we can't change that. Right now we're annotating "mixed" with a docblock. So yes, a "mixed" type is greatly appreciated when dealing with user input. Thanks! On Mon, Apr 20, 2020 at 6:41 PM Guilliam Xavier <guilliam.xavier@gmail.com> wrote:

Dan Ackroyd

6 years ago
On Mon, 20 Apr 2020 at 16:17, Larry Garfield <larry@garfieldtech.com> wrote:
> I... cannot actually envision what code would actually accept that mess. :-)
var_dump() would be one example. Also caches that can store any userland value would be another reasonably common use. The general pattern is when you're handling someone else's 'data' and have no restrictions on what type that data should be. That's actually the use-case that prompted me to help draft this RFC.
> now that we have Union types what places are > there where the currently available type declarations are insufficient?
A type that explicitly allows any type is more forwards compatible than writing out a union type. Compare this: var_dump( mixed $expression [, mixed $... ] ) : void to: var_dump( null|bool|int|float|string|array|object|resource $expression [, null|bool|int|float|string|array|object|resource $... ] ) : void If/when we add an 'enum' type that is not a child type of any of the current types, the signature of that function doesn't need to change if it uses mixed, rather than the written out union type. Also, the 'fitting on a line' problem. cheers Dan Ack

Guilliam Xavier

6 years ago
On Mon, Apr 20, 2020 at 4:15 PM Sara Golemon <pollita@php.net> wrote:
> > For the long term good of the language I'd prefer type aliases (or typedefs > or usings or whatever you want to call them. > > use mixed = null|bool|int|float|string|array|object|resource; > use scalar = null|bool|int|float|string; > use number = int|float; > > That said, baking 'mixed' in as an implicit alias of the above isn't > problematic for that future.
The `scalar` example should be `bool|int|float|string`, without `null`. And for `mixed`, as already said, we cannot use `resource` in union types. All the more reason to standardize those "aliases" in core?
-- Guilliam Xavier

Côme Chilliet

6 years ago
Le lundi 20 avril 2020, 09:15:24 CEST Sara Golemon a écrit :
> use mixed = null|bool|int|float|string|array|object|resource; > use scalar = null|bool|int|float|string;
I’m wondering if null should maybe be left out of these, since ?mixed and ?scalar can be used for this?
-- Côme Chilliet FusionDirectory - https://www.fusiondirectory.org

Guilliam Xavier

6 years ago
On Tue, Apr 21, 2020 at 11:10 AM Côme Chilliet <come.chilliet@fusiondirectory.org> wrote:
> > Le lundi 20 avril 2020, 09:15:24 CEST Sara Golemon a écrit : > > use mixed = null|bool|int|float|string|array|object|resource; > > use scalar = null|bool|int|float|string; > > I’m wondering if null should maybe be left out of these, since ?mixed and ?scalar can be used for this?
For mixed, this has been discussed several times, it's defined as the union of *all* value types (void aside), *including* null, according to its usage in phpDoc (and in Hack, which also has a nonnull type such that mixed is equivalent to ?nonnull, cf https://docs.hhvm.com/hack/types/nullable-types). For scalar, I already replied (https://externals.io/message/109715#109723) that it should not include null indeed (according to https://www.php.net/manual/en/language.types.intro.php and https://www.php.net/manual/en/function.is-scalar.php).
-- Guilliam Xavier

Gabriel Caruso

6 years ago
On Mon, 20 Apr 2020 at 13:18, Dan Ackroyd <Danack@basereality.com> wrote:
> Hi Internals, > > Here is an RFC for adding a 'mixed' type to the language: > https://wiki.php.net/rfc/mixed_type_v2 > The RFC builds on an earlier draft by Michael Moravec. > > Part of the motivation for pursuing this RFC was my recent experience > in upgrading an application to PHP 7.4. > > Being able to add types to the application made the code much easier > to reason about, but there were places where I couldn't add type info > due to the lack of mixed. That made it hard to see if that piece of > code had been upgraded (but type info couldn't be added), or if that > code still needed to be upgraded. > > cheers > Dan > Ack > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php > >
Hello Danack Has the type `any` been considered? I've discussed that in the implementation Pull Request with Máté. Would it be too much to create a sub-voting for the type used here? Best regards,

Ilija Tovilo

6 years ago

Ilija Tovilo

6 years ago
Sorry, I don't know what's wrong with my mail client, it just sent the email with no content. Here's it again. Hi Dan
> Here is an RFC for adding a 'mixed' type to the language: > https://wiki.php.net/rfc/mixed_type_v2 > The RFC builds on an earlier draft by Michael Moravec.
I don't have a whole lot to add other than I appreciate this RFC. We currently can't differentiate between "I didn't bother documenting this" and "yes, I actually accept all types". One note: I was wondering if the following code throws an error (it does): function foo(): mixed {} foo(); //> Uncaught TypeError: Return value of foo() must be of the type mixed, none returned I found the answer in the tests. Might be worth mentioning in the RFC. Regards, Ilija

Bob Weinand

6 years ago
Hey Dan, this, I consider one of the few concepts which should never make it into PHP. In particular, the main problem with mixed is that it is a very easy "I have no idea how to type that properly, so just let's use mixed". And really, in general, except for some debug functions, mixed is just an excuse to not use proper generics. I cannot think of non-debug scenarios where we are juggling truly unknown types where the type is unidirectional. (Uni-directional means: there is no corresponding getting/forwarding function for an input.) Mixed is in almost every case just patching the holes in PHPs type system. And as such, I'd rather promote RFCs trying to properly fix the gaps in the type system than supporting mixed. Mixed is a hack, do not use mixed. Bob P.s.: If you want to migrate your types and have an overview of what's already migrated, maybe just add a comment // type-migrated before or similar? But that's seriously not the business of the language.

Lynn

6 years ago
On Fri, Apr 24, 2020 at 2:12 PM Bob Weinand <bobwei9@hotmail.com> wrote:
> Mixed is in almost every case just patching the holes in PHPs type system. > And as such, I'd rather promote RFCs trying to properly fix the gaps in the > type system than supporting mixed. > > Mixed is a hack, do not use mixed. >
Heya Bob, I maintain lots of legacy code and I cannot add return types despite being truly mixed. Mixed is not a hack, it's a scenario that frequently happens. There are lots of use-cases where we explicitly want to mark it as such as it truly accepts anything. Would I use it in new code? Pretty much never, as `string|int` would already cover the majority of cases, especially where ints are represented by strings. I would love to see mixed being added as it lets me remove a lot of docblocks that are only added so I can indicate mixed. I disagree that it's patching holes, it's filling a gap that's currently missing something. Regards, Lynn

Rowan Collins

6 years ago
On Fri, 24 Apr 2020 at 13:18, Lynn <kjarli@gmail.com> wrote:
> I would love to see mixed being added as it lets me remove a lot of > docblocks that are only added so I can indicate mixed. I disagree that it's > patching holes, it's filling a gap that's currently missing something. >
I realise it's partly a matter of style, but if I were benevolent dictator of a legacy code base, I'd prefer to keep the docblocks, and mandate that all uses of "mixed" should include a comment describing what the parameter / return type represents / is related to. Similarly, I wouldn't delete a docblock for a return type of "array", because I'd want more specific details (either using "type[]" syntax, "list<type>" syntax, or a comment describing the "shape" of the array). I'm not as strongly against adding "mixed" to the language as Bob, but I'm not convinced I'd ever bother using it. Regards,
-- Rowan Tommins [IMSoP]

Matthew Brown

6 years ago
> > I'm not as strongly against adding "mixed" to the language as Bob, but I'm > not convinced I'd ever bother using it. >
I'm opposed to the use mixed in codebases – I try as best I can to remove it from any code I come across, and a static analysis tool I've built flags the use of mixed types whenever a more specific type is preferable. I even have an opt-in website devoted to tracking the percentage of non-mixed types in open-source projects, e.g. https://shepherd.dev/github/sebastianbergmann/phpunit Nevertheless, I think mixed should be available as a type hint for the extreme cases mentioned in this thread (e.g. serialisation). A type system without an explicit mixed type feels incomplete to me.

Dan Ackroyd

6 years ago
Bob Weinand wrote:
> Mixed is a hack, do not use mixed. > ... > As such the introduction of mixed is pretty much necessary. > I'm actually in favor of introducing it.
Matthew Brown wrote:
> I'm opposed to the use mixed in codebases ... > A type system without an explicit mixed type feels incomplete to me.
'I am agree with all'. Mixed is a vital thing....that should be used as little as possible. Marco Pivetta wrote:
> I think making `mixed` very painful to write may be a big advantage.
Everything is a tradeoff, and I think one of the things that PHP does well right is allowing people to choose their own tradeoffs, rather than having a "one true way" of doing things in PHP. Exceptions, eval(), annotations/attributes, and the mixed type are all things that have a vital place, even though they can be used inappropriately. Making something like this painful to use seems a bad choice. It's different from things like json_last_error() or preg_last_error() where doing the easier thing (of not checking those) is always the wrong thing. In particular for people like: Lynn wrote:
> I maintain lots of legacy code and I cannot add > return types despite being truly mixed. Mixed is not a > hack, it's a scenario that frequently happens.
making things more painful for people maintaining legacy code seems like definitely a bad choice. Gabriel Caruso wrote:
> Has the type `any` been considered?
Yes. I think mixed is the better choice for now. There's just so much widespread use of 'mixed' in PHP core, extensions, documentation and userland code that even if 'any' were a slightly better choice long term, taking a choice that would probably be multiple years before it paid off it's cost, seems bad. Ilija Tovilo wrote:
> One note: I was wondering if the following > code throws an error (it does):
Thanks, updated the RFC. cheers Dan Ack

Benas IML

6 years ago
Hello, Is there any update on the RFC? Given that there isn't much discussion and 2 weeks have passed, I believe it's safe to move this into a voting phase. Best regards, Benas Seliuginas

Dan Ackroyd

6 years ago
Benas IML wrote:
> Is there any update on the RFC? Given that there isn't much discussion and 2 > weeks have passed, ...
The "two weeks" thing is a minimum. I personally would prefer if most discussions were longer than that whenever possible. It's entirely possible for someone to not have time to even look at PHP internals during any particular two week period, either through being busy, or being on holiday, or just being fed-up with internals and not wanting to look at it for a bit. But yes, as the "Ensure correct signatures of magic methods" RFC is being held up by this one, the plan is to open voting tomorrow. cheers Dan Ack

Bob Weinand

6 years ago
Actually, I forgot that for proper generics implementations, collections etc. will obviously need to specify "allowing any type". As such the introduction of mixed is pretty much necessary. As in class Foo<A, B> { … } $foo = new Foo<mixed, int>; As such, I'm actually in favor of introducing it. Bob

Markus Fischer

6 years ago
On 24.04.20 16:33, Bob Weinand wrote:
> Actually,
Really had to laugh, reading your previous and then this mail :-)
> > I forgot that for proper generics implementations, collections etc. will obviously need to specify "allowing any type". As such the introduction of mixed is pretty much necessary. > > As in class Foo<A, B> { … } $foo = new Foo<mixed, int>; > > As such, I'm actually in favor of introducing it.
Re-quote:
> "allowing any type"
That would make the case for the `any` type instead of mixed; IMHO much more clear. - Markus

moliata

6 years ago
I personally would stick to `mixed`. It's used extensively in the official PHP documentation and has grown with the language. Heck, even static analysis tools and billions of PHPDoc comments (e. g. Laravel, CakePHP, Yii) use `mixed` type. Switching to `any` just doesn't feel right. Oh and well, I also think that `mixed` makes more sense. Best regards, Benas Seliuginas ‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐ On Friday, April 24, 2020 5:48 PM, Markus Fischer <markus@fischer.name> wrote:

Marco Pivetta

6 years ago
Hey Dan, On Mon, Apr 20, 2020, 13:18 Dan Ackroyd <Danack@basereality.com> wrote:
> Hi Internals, > > Here is an RFC for adding a 'mixed' type to the language: > https://wiki.php.net/rfc/mixed_type_v2 > The RFC builds on an earlier draft by Michael Moravec. > > Part of the motivation for pursuing this RFC was my recent experience > in upgrading an application to PHP 7.4. > > Being able to add types to the application made the code much easier > to reason about, but there were places where I couldn't add type info > due to the lack of mixed. That made it hard to see if that piece of > code had been upgraded (but type info couldn't be added), or if that > code still needed to be upgraded. >
How much would you like/be adverse to a rector rule that changes `mixed` into a long union type (without `resource` in it)? Considering above posts, `mixed` is effectively `null|bool|string|int|float|array|object`, and that the language has the ability to use this type in 8.0, I think making `mixed` very painful to write may be a big advantage. `resource` is still a massive PITA: not sure if it can be removed within the decade. Heck, we may even deprecate signature-less parameters and return types in a very far future 💪

Matthew Brown

6 years ago
> > How much would you like/be adverse to a rector rule that changes `mixed` > into a long union type (without `resource` in it)?
> Considering above posts, `mixed` is effectively > `null|bool|string|int|float|array|object|resource`, >
At runtime those things are effectively the same, but in the world of types mixed has its own distinct meaning – I'd be very averse to any sort of corresponding replacement.

moliata

6 years ago
Actually, it's not quite possible to declare a `mixed` type using union types given that it's not possible to make properties as callable (please take a look at my "Typed callable properties" post in the mailing list). As such, if we wanted to make a property hold a callable, we would have to fallback to just not using a type hint at all. Correct me if I'm wrong but this behavior is addressed in the RFC and we can pass callables to properties that are declared as `mixed`, right? Best regards, Benas Seliuginas ‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐ On Friday, April 24, 2020 6:09 PM, Matthew Brown <matthewmatthew@gmail.com> wrote:

Marco Pivetta

6 years ago
Hey moliata, On Fri, Apr 24, 2020 at 5:27 PM moliata <moliata@protonmail.com> wrote:
> Actually, it's not quite possible to declare a `mixed` type using union > types given that it's not possible to make properties as callable (please > take a look at my "Typed callable properties" post in the mailing list). As > such, if we wanted to make a property hold a callable, we would have to > fallback to just not using a type hint at all. > > Correct me if I'm wrong but this behavior is addressed in the RFC and we > can pass callables to properties that are declared as `mixed`, right? >
The only limitation right now is `resource`: `callable` is always either an `array`, a `string` or an `object` that implements `__invoke`, so `callable` is a subtype of the union type mentioned few posts above. Marco Pivetta http://twitter.com/Ocramius http://ocramius.github.com/

moliata

6 years ago
Hello, I did some tests and in fact it seems you're right. Thank you for letting me know, didn't know! Best regards, Benas Seliuginas ‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐ On Friday, April 24, 2020 6:44 PM, Marco Pivetta <ocramius@gmail.com> wrote: