Skip to content
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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added mixed argument type & return type #2603

Closed
wants to merge 2 commits into from
Closed

Conversation

@Majkl578
Copy link
Contributor

@Majkl578 Majkl578 commented Jun 30, 2017

This is a proof of concept for built-in mixed type for parameter types and return types.
The behavior of mixed type matches the behavior when no type is specified (thus being implicitly mixed).
Primary motivation for having explicit mixed type is consistence and easier static analysis. In PHP 7.2, mixed types are unfortunately the only type that could not be type hinted upon (true, resource as well, but its future is unclear).
I believe having mixed type would polish the code interface even more, thus having code with 100% explicit type hint coverage.


Before:

<?php
function foo($arg) {
    return $arg;
}

Now:

<?php
function foo(mixed $arg): mixed {
    return $arg;
}

(Note that I barely know the PHP internals so this may be entirely wrong approach.)


TODOs:

  • disalow ?mixed at compile time?
  • add more tests?

This probably needs an RFC, although mixed is already a reserved type. Since I don't have permission to create RFCs, a sponsor would be welcomed (anyone? 馃槆).
Not sure whether it'd be too late for inclusion in 7.2 in case it'd be accepted (probably not yet since there's not even a beta yet).

What do you think? 馃殺

@krakjoe krakjoe added the RFC label Jul 4, 2017
@Majkl578
Copy link
Contributor Author

@Majkl578 Majkl578 commented Jul 6, 2017

@sgolemon @remicollet Hi, do you think this would still be acceptable for 7.2?
Scheduled feature freeze for 7.2 is on July 20th and as RFCs require 14 days discussion period + 7-14 days voting period, it's unfortunately after the deadline. :/
But since this would be a tiny language change with no BC breaks, just an alias to existing behavior, I think it'd be okay to eventually fine to introduce in later beta. Or not?

@Majkl578 Majkl578 force-pushed the Majkl578:mixed-type branch 2 times, most recently from 5c0b355 to e1142bb Jul 6, 2017
@KalleZ
Copy link
Member

@KalleZ KalleZ commented Jul 6, 2017

I was recently hit by this oddity, I actually thought we reserved it and made it possible with the introduction in 7.0, get this in!

@Majkl578
Copy link
Contributor Author

@Majkl578 Majkl578 commented Jul 6, 2017

I actually thought we reserved it and made it possible with the introduction in 7.0,

mixed is reserved as of PHP 7.0, but it has never been implemented (pretty much like object). :/ Having object in 7,2 is just another reason why this would be nice to have in 7.2 as well. 馃憤

@Majkl578 Majkl578 force-pushed the Majkl578:mixed-type branch from e1142bb to 60aa68b Jul 11, 2017
@Majkl578
Copy link
Contributor Author

@Majkl578 Majkl578 commented Jul 19, 2017

Ping @sgolemon @remicollet - what do you think about this, is it already too late or would it be acceptable as a self-contained addition aliasing current behavior?
Note that I've requested Wiki karma in php.internals to write an RFC over a week ago and got absolutely no reply so far... 馃槥

@krakjoe
Copy link
Member

@krakjoe krakjoe commented Jul 19, 2017

You have missed the official feature freeze (yesterday), while the branch is in pre-release mode, we can't do anything.

The thing to do is let the RFC process run, we can see where we are at the end of that once all discussion and voting is done. It may be acceptable to merge once GA, although this is not my call.

You have permission to write an rfc on wiki.

@Majkl578
Copy link
Contributor Author

@Majkl578 Majkl578 commented Jul 19, 2017

@b1rdex
Copy link
Contributor

@b1rdex b1rdex commented Dec 1, 2017

@Majkl578 have you started RFC discussion?

@Majkl578
Copy link
Contributor Author

@Majkl578 Majkl578 commented Dec 1, 2017

Not yet, it's not finished and there is plenty of time for 7.3. :)

@Majkl578 Majkl578 force-pushed the Majkl578:mixed-type branch from 60aa68b to e6921a9 Dec 19, 2017
@Majkl578
Copy link
Contributor Author

@Majkl578 Majkl578 commented Dec 19, 2017

I must admit I have no clue why one build target fails on two of these tests and the other one is green, both Travis and AppVeyor. It was fine before rebase in which I only changed type code in zend_types.h. :/
Can't reproduce any failure localy... Could anyone provide any pointers? Thanks.

@Majkl578
Copy link
Contributor Author

@Majkl578 Majkl578 commented Dec 19, 2017

@jordyvandomselaar
Copy link

@jordyvandomselaar jordyvandomselaar commented Dec 19, 2017

Why would you typehint a non type? Then just don't typehint -.-, this undoes everything typehinting was supposed to fix.

@b1rdex
Copy link
Contributor

@b1rdex b1rdex commented Dec 20, 2017

@jordyvandomselaar @carusogabriel answer for your question is in first comment 鈥斅爐his feature is supposed to add more clearance to code to show where mixed is really accepted and where just no type hint specified.

@jordyvandomselaar
Copy link

@jordyvandomselaar jordyvandomselaar commented Dec 20, 2017

鈥 And not typehinting wouldn't be clear enough? No type hints === no specified type === throw in whatever you'd like.

@Majkl578
Copy link
Contributor Author

@Majkl578 Majkl578 commented Dec 20, 2017

I am not going to argue with people who don't understand difference between mixed type and no type, sorry. Look at code that uses 7.1 and maintains BC for another X years. Example: class with 10 recently added methods with typehints, 10 old methods without anything to maintain BC. Now tell anyone whether mixed is intentional or not.

@jordyvandomselaar
Copy link

@jordyvandomselaar jordyvandomselaar commented Dec 20, 2017

There isn't a difference between no type and a mixed type. Intentional or not, old code will still accept any type, a.k.a. mixed type. If you're upgrading to php 7.2 I suggest you refactor code that ends up using type hints anyways.

@Htarlov
Copy link

@Htarlov Htarlov commented Dec 22, 2017

I'm not sure it's very good idea.

You always can add comment to hint that type hint is ommited on purpose (with some inforation why it was done).

With mixed type there will be situations when someone asks "please add type hints to your code" or there will be a requirement that code has to be with type hints and then a programmer will add massive amounts of "mixed" type hints - "because deadline".

}
}

class Baz extends bar {

This comment has been minimized.

@carusogabriel

carusogabriel Jan 20, 2018
Member

Minor: bar in lower case

This comment has been minimized.

@Taluu
Copy link

@Taluu Taluu commented May 14, 2018

Bumping, would like to see that one in 7.3 if possible... Because I transformed a few of my interfaces to mixed type, where it makes sense. and not adding any typehint kinda annoys me.

@ostrolucky
Copy link

@ostrolucky ostrolucky commented May 14, 2018

@Htarlov has very good point. Developers will just start adding mixed typehints mindlessly and everybody will think they are mixed by purpose.

@Taluu
Copy link

@Taluu Taluu commented May 14, 2018

IMO it's the same really as typing nothing, except that if nothing is typed it really means "meh don't care". with the typehint, it's "tried to care, up to you to care to check". It's semantics, really.

@Majkl578
Copy link
Contributor Author

@Majkl578 Majkl578 commented May 14, 2018

@Htarlov has very good point. Developers will just start adding mixed typehints mindlessly and everybody will think they are mixed by purpose.

If anyone wants to shoot themselves into foot, it's their choice.

Similar with Error, you can throw TypeError on your own although it's probably not a good idea.

@jordyvandomselaar
Copy link

@jordyvandomselaar jordyvandomselaar commented May 15, 2018

I still don't think it adds anything but bloat. It's functionality is none, it doesn't help the developer- nor PHP at all. Mixed is implicit if there is no type hint. It literally has no upsides at all.

@Majkl578
Copy link
Contributor Author

@Majkl578 Majkl578 commented May 15, 2018

It's functionality is none

If nothing else, it forbids mixing mixed and void.

it doesn't help the developer

Quite the contrary: the developer instantly knows it's explicitly expected to accept/return mixed, instead of being forgotten type hint or legacy PHP 5 pre-7.1/7.2 code.

Mixed is implicit if there is no type hint.

Don't forget that no return type means EITHER mixed OR void.

@JanTvrdik
Copy link

@JanTvrdik JanTvrdik commented May 15, 2018

Don't forget that no return type means EITHER mixed OR void.

mixed (being the top type) is supertype of void (being a unit type).

@Majkl578
Copy link
Contributor Author

@Majkl578 Majkl578 commented Jun 30, 2018

Are you arguing that mixed does/should not include void?

Yes, please read the discussion/RFC.

@Majkl578
Copy link
Contributor Author

@Majkl578 Majkl578 commented Jul 3, 2018

FYI: Based on the discussion and clearing up the inheritance issue with void, we're postponing this for 7.4/8.0 (whichever comes first).

@Majkl578
Copy link
Contributor Author

@Majkl578 Majkl578 commented Feb 8, 2019

Published new version: https://wiki.php.net/rfc/mixed-typehint
This PR is not updated yet.

/* Child defines a type, but parent doesn't, violates LSP, unless it's a mixed type */
if (ZEND_TYPE_CODE(fe_arg_info->type) == IS_MIXED) {
return 1;
}
return 0;

This comment has been minimized.

@carusogabriel

carusogabriel Feb 8, 2019
Member

I believe this can be simplified:

Suggested change
return 0;
return ZEND_TYPE_CODE(fe_arg_info->type) == IS_MIXED;
@@ -359,6 +362,9 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c
if (proto->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
/* Removing a return type is not valid. */
if (!(fe->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
if (ZEND_TYPE_CODE(proto->common.arg_info[-1].type) == IS_MIXED) {
return 1;
}
return 0;

This comment has been minimized.

@carusogabriel

carusogabriel Feb 8, 2019
Member

I believe this can be simplified:

Suggested change
return 0;
return ZEND_TYPE_CODE(proto->common.arg_info[-1].type) == IS_MIXED;
@dugajean
Copy link

@dugajean dugajean commented Apr 10, 2019

I would like to see this merged

@azjezz
Copy link

@azjezz azjezz commented Apr 23, 2019

HUGE +1, would love to see this in PHP 7.4 or maybe 8.0, mixed would be extremely useful, specially when we get generics.

Example :

<?php declare(strict_types=1);

interface Normalizer<T> {
  public function normalize(T $data): array;
}

function foo(Normalizer<User> $normalizer, User $user): array {
  return $normalizer->normalize($user);
}
function bar(Normalizer<string> $normalizer, string $data): array {
  return $normalizer->normalize($data);
}
function baz(Normalizer<int> $normalizer, int $number): array {
  return $normalizer->normalize($number);
}
final class DefaultNormalizer implements Normalizer<mixed> {
  public function normalize(mixed $data): array {
   // code
  }
}

$normalizer = new DefaultNormalizer();
foo($normalizer, new User()); // works
bar($normalizer, 'bar'); // works
baz($normalizer, 123); // works
@azjezz
Copy link

@azjezz azjezz commented Apr 26, 2019

UPDATE : if PHP got generics at some point + #4073 + #2603 , all iterables that are not type hinted, should be considered iterable<arraykey, mixed>

e.g :

function foo(array $arr): void {}

is same as :

function foo(array<arraykey, mixed> $arr): void {}
@Majkl578
Copy link
Contributor Author

@Majkl578 Majkl578 commented Apr 26, 2019

@azjeez Yes, it applies to generics in general, not just iterable or arrays. I'll make that clear in the RFC too.

@azjezz
Copy link

@azjezz azjezz commented Apr 26, 2019

@Majkl578 , this should not be allowed with generics :

interface Foo<T> {}

function foo(Foo $foo): void {}

<T> would need to be specified, specially when there's type constrain :

interface Foo<T as Bar> {}

but i think iterable, ArrayAccess, Iterator ... etc ( existing interfaces / types that use generics ), should have an exception, otherwise requiring <Tk, Tv> will be a HUGE BC break.

@Majkl578
Copy link
Contributor Author

@Majkl578 Majkl578 commented Apr 26, 2019

@azjeez That's something up to the Generics RFC to define, in case mixed gets accepted.

@boesing
Copy link

@boesing boesing commented Aug 2, 2019

I would prefer having an or condition for multiple types instead of mixed which could be any type.
I dont think that methods, which return mixed, return more than a specific number of pre-defined types.

Most of the time its probably something like:

/** @return string|bool */
public function foo(): mixed;

So a declaration like would make more sense to me.

public function foo(): string | bool;
@boesing
Copy link

@boesing boesing commented Aug 2, 2019

@kunicmarko20 exactly. Would prefer these types over mixed as mixed is too generic.

@nikic
Copy link
Member

@nikic nikic commented Jan 10, 2020

As we now have union types, it probably makes sense to bring this up again.

@Girgias
Copy link
Member

@Girgias Girgias commented Jan 10, 2020

As we now have union types, it probably makes sense to bring this up again.

Isn't the main contention point as to whether it should include null or not?

@azjezz
Copy link

@azjezz azjezz commented Jan 10, 2020

Isn't the main contention point as to whether it should include null or not?

IMHO, mixed should include everything, basically :

function foo($bar): void {}

is same as :

function foo(mixed $bar): void {}

note that hacklang already has another type called nonnull which doesn't include null mixed - null : https://docs.hhvm.com/hack/built-in-types/nonnull

@jordyvandomselaar
Copy link

@jordyvandomselaar jordyvandomselaar commented Jan 12, 2020

As we now have union types, it probably makes sense to bring this up again.

If we have union types, this doesn't solve any usecases anymore?

@Majkl578 Majkl578 closed this Jan 12, 2020
@Majkl578 Majkl578 reopened this Jan 12, 2020
@Majkl578
Copy link
Contributor Author

@Majkl578 Majkl578 commented Jan 12, 2020

@jordyvandomselaar With union types it becomes an alias, a sugar, similar to iterable or nullable types. The use case is still to express explicit interest in mixed value without having to write a full union everywhere.
(Accidentally closed on phone, this PR becomes a bit unmaintainable in there. 馃槄)

@nikic
Copy link
Member

@nikic nikic commented Jan 12, 2020

Note that it's not actually possible to write out a mixed type as a union right now, because you're not permitted to type against resource for forward-compatibility reasons.

@jordyvandomselaar
Copy link

@jordyvandomselaar jordyvandomselaar commented Jan 13, 2020

@Majkl578 but how would you have the compiler handle it? If you use something, would it complain that you have not handled any other type in your project that it might return? I use Laravel for example, should the compiler complain that I have not checked against a Laravel collection?

I know TypeScript for example, tells me I forgot to check for null when using something that is nullable.

@kocsismate
Copy link
Member

@kocsismate kocsismate commented Mar 15, 2020

@Majkl578 What's your plan with this? Will you propose mixed for PHP 8?

@acasademont
Copy link
Contributor

@acasademont acasademont commented Mar 26, 2020

This would be great indeed :)

@VincentLanglet
Copy link

@VincentLanglet VincentLanglet commented Apr 19, 2020

A mixed argument type would be great.

My example is simple but it would be definitely better to write

function foo(mixed $value): mixed {
   return $value
}

Rather than

function foo($value) {
   return $value
}

Which could be changed to

function foo($value) {
   return;
}

Without any error.

Plus arguing that

function foo($value) {}

And

function foo(mixed $value) {}

Are the same, is like saying

function foo($value) {}

And

/**
 * @param mixed $value
 */
function foo($value) {}

Are the same.
IMHO, it's not. I see interest in the documentation.

@Chi-teck
Copy link

@Chi-teck Chi-teck commented Apr 21, 2020

I think without mixed it is hard for static analyzers to identify whether or not missing type hint is a mistake. Also it can be useful when extending/decorating legacy code without type hints.

}
}

class Baz extends bar {

This comment has been minimized.

@nikic
Copy link
Member

@nikic nikic commented May 23, 2020

New implementation in #5313 has been merged, so closing this one.

@nikic nikic closed this May 23, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet