Skip to content

Add support for the mixed type #5313

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed

Conversation

kocsismate
Copy link
Member

@kocsismate kocsismate commented Mar 28, 2020

@nikic
Copy link
Member

nikic commented Mar 28, 2020

This needs tests for how mixed interacts with inheritance / variance.

@kocsismate
Copy link
Member Author

Yeah, I know. It was just too late when I finished this. 😊

@kocsismate
Copy link
Member Author

kocsismate commented Mar 29, 2020

@nikic I've just added the missing variance tests :) I believe only "auxiliary" stuffs like reflection tests needs to be added now, but correct me if I'm wrong.

@kocsismate kocsismate changed the title [WIP] Add support for the mixed type Add support for the mixed type Mar 29, 2020
Copy link
Contributor

@carusogabriel carusogabriel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kocsismate Have you consider the type any instead of mixed?

I have a feeling that this name will be clearer, and we don't have the bias of the famous "mixed and no return type, what is the difference"?

@kocsismate kocsismate force-pushed the mixed-type branch 2 times, most recently from 5febb2f to ad7e93a Compare March 30, 2020 09:14
@nikic
Copy link
Member

nikic commented Mar 30, 2020

Just to double check, under this implementation mixed and no type are equivalent apart from a) reflection and b) property initialization. Is that right?

@kocsismate
Copy link
Member Author

kocsismate commented Mar 30, 2020

@nikic We can say yes.. Although there is one more exception: return types, in which case the no return type would be equivalent to mixed|void (but mixed|void is not part of the RFC - at least yet).

@nikic
Copy link
Member

nikic commented Mar 30, 2020

I see, so that also means that you can't go mixed -> no type... (https://github.com/php/php-src/pull/5313/files#diff-48f407b29ba53b48ecba8911907fed25)

@nikic
Copy link
Member

nikic commented Mar 30, 2020

I guess that's fine. Adding a return type always requires it to be specified on inheriting methods as well, so nothing new here.

@kocsismate You might want to avoid generating a VERIFY_RETURN opcode in case of mixed type.

@kocsismate
Copy link
Member Author

@nikic Thanks for the hint with the opcode! We'll come up with an RFC first, then I'll continue polishing the implementation if the RFC changes or gets accepted ^^

@krmgns
Copy link

krmgns commented Apr 9, 2020

I wish a better suggestive / expressive keyword was chosen, e.g. "Any" like in TypeScript. Mixed sounds like mixing the things, like union types. So IMHO it will lead the devs being confused such: "what the type was / will mixed with".

@kocsismate
Copy link
Member Author

@K-gun Yes, any is probably a better name, but mixed is in the culture of PHP for so long time (e.g.: in the official documentation, or in PHPDoc) that it would be a mistake not to go with it.

@acasademont
Copy link
Contributor

Thanks for your work on reviving this! Hope we can get it for 8.0 :D

@Majkl578
Copy link
Contributor

Majkl578 commented Apr 19, 2020

It's a surprise for me to find this PR. I am not very happy to see my work stolen instead of reaching out to me (Twitter or even an e-mail) first. Especially when done by a PHP member directly (who could even push directly to my PR).

I actually dropped @nikic an e-mail last month to see how to move some RFCs (including mixed) forward for PHP 8 but didn't really want to insist on it and ping him here or on Twitter directly.

@kocsismate
Copy link
Member Author

@Majkl578 Please have a look again at your PR where I asked about your plans with the mixed type. Because I received no answer for weeks (maybe months now), I moved forward. Furthermore, your last activity was in January, so I think you had plenty of time to show any intention to work on the topic.

Also, your work is not stolen, since union types required a completely different implementation.

@Majkl578
Copy link
Contributor

Majkl578 commented Apr 19, 2020

I am not very active on GitHub or in OSS in general in the past year.

Because I received no answer for weeks (maybe months now), I moved forward.

I am not aware of any deadlines for responses being set. You could've contacted me on Twitter (my DMs are open) and we could've talked about the RFC itself and how to improve it and move towards voting. But you did not. So I expect you'll now take over my RFC as well?

(If I was not interested in finishing the RFC the PR would be already closed and RFC withdrawn/inactive.)

@VincentLanglet
Copy link
Contributor

Also, your work is not stolen, since union types required a completely different implementation.

It's not because you change the lyrics of a song that it's not a steal when you use it.
Giving credit to @Majkl578 could be a minimum.

Support for mixed type would be great. I can't wait to use it !
I hope this situation won't hurt the introduction of the new type.

@krmgns
Copy link

krmgns commented May 7, 2020

@K-gun Yes, any is probably a better name, but mixed is in the culture of PHP for so long time (e.g.: in the official documentation, or in PHPDoc) that it would be a mistake not to go with it.

@kocsismate; I suppose, historical reasons cannot be an argument to go with them. If this were true, the world would remain as it was in the history. This is same for cultural perspective. Eg. "real" type removed but it was in PHP culture for years, and I can bring many examples here like that. And also we all know that the official documentations are untouched for decades, unless any comment made like that ie: "with version 7.4 bla bla" (yes it is true, my comment is removed from strip_tags document and added 7.4 note a few weeks ago). And withal, I can say that; in many open source library, I have seen billion and billion of PHPDoc's that use any keyword during my 15 years of PHP experience so far.

So, here is my humble recommendation; please, allow people to use both any and mixed and let them choose what they would like to. Or simply allow them define types like eg: type number = int|float; etc.

Meanwhile, seems any is not unfamiliar to you: if ((type_mask == MAY_BE_ANY) ....

All beside I have a question with the source below; is it forbidden writing something like this foo(?any $x) or foo(any $x = null), and if it is forbidden how can we define a variable that may take any type of value but also accepts null.

Source:

if ((type_mask == MAY_BE_ANY) && allow_null) {
    zend_error_noreturn(E_COMPILE_ERROR, "Type mixed cannot be nullable");
}

Source link: https://github.com/php/php-src/pull/5313/files#diff-3a8139128d4026ce0cb0c86beba4e6b9R5671

A simple use case for nullables:

function find_post(?any $max_id = null): ?array {
    if (is_null($max_id)) 
        return db_find("select * from `posts` order by `id` desc limit 1");

    if (!is_numeric($max_id)) // more strict control maybe
        return null;
    
    if (is_string($max_id)) 
        $max_id = intval($max_id);

    return db_find("select * from `posts` where `id` < {$max_id} order by `id` desc limit 1");
}

@moliata
Copy link
Contributor

moliata commented May 7, 2020

Hello @K-gun,

  1. I don't think it's necessary to address the any/mixed situation again as that is done in the RFC. But TL;DR mixed is used much much more in the PHP community than any and as such, mixed is a better option.

  2. Speaking of type aliasing (e. g. use type number as int|float;), that is not the scope of this RFC. Moreover, most PHP contributors just don't have enough time to work on every single feature that people want. So, if you want type aliasing, you can either wait for someone else to implement it or make a PR yourself.

  3. ?mixed and mixed|null is not allowed since null is already part of mixed. So, you can already pass null to parameters declared as mixed. I would also like to mention that a type does not need to be nullable in order to have a default value of null. So this is also perfectly legal: function test(string $test = null): void {}.

Best regards,
Ben
P.S: this reply isn't supposed to be harsh, so please don't take it as such.

@kocsismate
Copy link
Member Author

Thanks @moliata for the eloquent answer! I agree with all your points. :)

@krmgns
Copy link

krmgns commented May 8, 2020

@moliata; even you were not the addressee of my comments and questions, thanks anyway for your reply.

  1. No one is pushing anyone to put any keyword into PHP, but only sharing ideas for the future of it. Nobody objected or argued (means PHP users, not internals) on fn keyword that used for arrow functions and now it shows itself in PHP with all its glory... So, as far as I know, there is no rule such: "take it what ever given to you".
    By the way, I wonder how much projects you have been involved that use mixed keyword in their docs, actually I could not find anything on your GH page that is related with your PHP background (not means my PHP background beats yours).

  2. No one is claiming that the type aliasing is in scope of this RFC, and no one is wanting something new. That was mentioned in some type-related RFC by Nikita already and I just wanted to mention about this mention hoping those related people to get pay attention, as a member of PHP's user-land and expecting that comes with PHP-next. Remember, when new types came to the PHP with 7.0 there were not void or nullables (?).
    At the same time, I know PHP contributors (internals) have no time for only PHP, they should have more job to do in their daily lives. So this is an open source project and they cannot dedicate their life to PHP contributions. Or, I do look like dim-sighted that much while looking from there.

  3. This part is the most misunderstood part by you. Types are used for two purposes and let me explain it with my modest knowledge;
    I. to speak to the system saying eg: x variable can take only y type (say int). And now system knows that if user uses a wrong type then system warns/errorizes/stops so on, and vice-versa.
    II. to speak to the user (that reads and uses the source code of programs that could be written by other users or himself/herself) saying eg: x variable can only take y type, and now user knows which type will be used. Also ? indicates, the variable accepts nulls. Otherwise see the I. explanation above.
    First, stuffing null (that even not a type) into a type keyword saying "since null is already part of mixed" is like giving someone a lemon who wanted Vitamin-C pills saying "it contains Vitamin-C already". Second, ? for a type and null as default for a variable, both make the source code more readable for its users. However, while all types and typed properties can take the nullable sign (?), not allowing it for this may be expressed with just one word: oddness.
    By the way, I do know that I do not need to use ? sign for a variable that has a null default. But, do you know while this is legal and ? is optional for (nullable) arguments, but not for typed properties? So, this is illegal int $x = null though. What, another oddness? Wait, you can write ?int $x = null and that will make $x nullable (and maybe, it never should be). What, another oddness or now your code is buggy? Anyway...

PS: This reply is not supposed to be harsh, so please do not take it as such.

--

PHP is called "The Orc Language" for years because of its oddnesses, adding more odd and exotic things will make it remain as it called. So, do I love PHP? Yes, more than all other languages even while thinking about switching to another language nowadays after that much time. But at the same time, I know the end the of the movie, Orcs lose...

@kocsismate kocsismate force-pushed the mixed-type branch 2 times, most recently from 5da1150 to 825b6a5 Compare May 20, 2020 09:40
@carusogabriel
Copy link
Contributor

Travis CI build succeed, but the statuses weren't port back to GitHub: https://travis-ci.org/github/php/php-src/builds/689173929.

@php-pulls php-pulls closed this in aec4c0f May 22, 2020
@kocsismate kocsismate deleted the mixed-type branch May 22, 2020 14:17
@carusogabriel
Copy link
Contributor

Thanks for this RFC @kocsismate @Danack, I'll now be able to work on mine at #4177 💛

Shall we also close #2603? I can't as I'm blocked by its author.

@TysonAndre
Copy link
Contributor

TysonAndre commented May 25, 2020

One thing I didn't see after a quick look at this PR or the RFC: Should Generators be allowed to have an explicit return type of mixed? I'd have assumed they should, because it's returning a value and omitting the return type is allowed

After building php 8 with this change:

php > function test(): mixed { yield 2; }
Fatal error: Generators may only declare a return type containing Generator, Iterator, Traversable, or iterable, mixed is not permitted in php shell code on line 1

also, with abstract class Base { abstract function test(): mixed }, this has the unexpected effect of forcing all subclasses of a subclass implemented as a generator to have a return type of Traversable or narrower.

@nikic
Copy link
Member

nikic commented May 25, 2020

@TysonAndre Nice catch! Mixed should indeed be permitted for generators.

TysonAndre added a commit to TysonAndre/php-src that referenced this pull request May 25, 2020
TysonAndre added a commit to TysonAndre/php-src that referenced this pull request May 25, 2020
Fixes an edge case overlooked in
php#5313

Generators are objects, so `object` should have also been allowed in addition to
`iterable` and `Traversable`
php-pulls pushed a commit that referenced this pull request May 26, 2020
Fixes an edge case overlooked in
#5313

Generators are objects, so `object` should have also been allowed in addition to
`iterable` and `Traversable`

Closes GH-5626
@carusogabriel carusogabriel added this to the PHP 8.0 milestone May 29, 2020
@dereuromark
Copy link

dereuromark commented May 30, 2020

?mixed and mixed|null is not allowed since null is already part of mixed

That is sad. Why not properly saying mixed does not include null, and give nullable the meaning the language could give it here too? Using ?mixed?
That would be way more consistent than this now IMO.

For me mixed sounds like a union type of several "something", and null doesn't make sense here.
Also, nullable for all other types (void excluded of course) is now clearly defined, why this exception here then? Currently mixed return type usually already is properly declared as

@return mixed|null

if it can be nullable and

@return mixed

Where you don't need an isset() check or alike in following code.

This creates an unnecessary amount of additional checks where they could be avoided.

See also https://wiki.php.net/rfc/union_types_v2

jrfnl added a commit to PHPCompatibility/PHPCompatibility that referenced this pull request Aug 23, 2020
As of PHP 8.0, `mixed` can be used as a parameter type for function declarations.

The RFC explicitly does not allow for the `mixed` type to be combined with the nullability indicator.
While in itself, that is not a cross-version compatibility issue, I have made a very conscious choice to add a check for this anyway as - while discouraged with `mixed` being a soft reserved keyword -, prior to PHP 8, a class _could_ be named `mixed`, so a `?Mixed` type hint referring to such a class could exist in code and would be a cross-version compatibility issue as since PHP 8 that will throw a "Fatal error: Mixed types cannot be nullable".

Refs:
* https://wiki.php.net/rfc/mixed_type_v2
* php/php-src#5313
* php/php-src@aec4c0f

Includes unit tests.
jrfnl added a commit to PHPCompatibility/PHPCompatibility that referenced this pull request Aug 23, 2020
As of PHP 8.0, `mixed` can be used as a return type for function declarations.

The RFC explicitly does not allow for the `mixed` type to be combined with the nullability indicator.
While in itself, that is not a cross-version compatibility issue, I have made a very conscious choice to add a check for this anyway as - while discouraged with `mixed` being a soft reserved keyword -, prior to PHP 8, a class _could_ be named `mixed`, so a `?Mixed` type hint referring to such a class could exist in code and would be a cross-version compatibility issue as since PHP 8 that will throw a "Fatal error: Mixed types cannot be nullable".

Refs:
* https://wiki.php.net/rfc/mixed_type_v2
* php/php-src#5313
* php/php-src@aec4c0f

Includes unit tests.
Includes removing the `testNoViolationsInFileOnValidVersion()` test as the sniff will now throw errors either way.
jrfnl added a commit to PHPCompatibility/PHPCompatibility that referenced this pull request Aug 23, 2020
As of PHP 8.0, `mixed` can be used as a type for property declarations.

The RFC explicitly does not allow for the `mixed` type to be combined with the nullability indicator.
While in itself, that is not a cross-version compatibility issue, I have made a very conscious choice to add a check for this anyway as - while discouraged with `mixed` being a soft reserved keyword -, prior to PHP 8, a class _could_ be named `mixed`, so a `?Mixed` type hint referring to such a class could exist in code and would be a cross-version compatibility issue as since PHP 8 that will throw a "Fatal error: Mixed types cannot be nullable".

Refs:
* https://wiki.php.net/rfc/mixed_type_v2
* php/php-src#5313
* php/php-src@aec4c0f

Includes unit tests.
@DriverCat
Copy link

@kocsismate Is it allowed to use mixed in union return type, like so:

@return mixed|\Illuminate\Contracts\Foundation\Application|\Illuminate\Http\Request

We need this in order to have IDE autocomplete for \Illuminate\Http\Request

@kocsismate
Copy link
Member Author

@DriverCat No, it isn't allowed in a type declaration. You can freely do so though in PHPDoc, but I'm not sure whether static analysers complain about it. However, unless your method returns other types besides the two classes, you might be able to get rid of mixed:

@return \Illuminate\Contracts\Foundation\Application|\Illuminate\Http\Request

@DriverCat
Copy link

@DriverCat No, it isn't allowed in a type declaration. You can freely do so though in PHPDoc, but I'm not sure whether static analysers complain about it. However, unless your method returns other types besides the two classes, you might be able to get rid of mixed:

@return \Illuminate\Contracts\Foundation\Application|\Illuminate\Http\Request

Thanks for the answer! Thats exactly the problem that it allows custom classes return.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.