-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Make intersection types nullable #7259
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
Conversation
The syntax should be either |
This syntax does not exist, 8.1 should not introduce it I believe. What exists is nullable types with a We do need nullable intersection types now, not in the future. |
It's not that There are also LSP concerns with allowing null on an intersection type. I don't know what needs to be handled there as I have not given it much thought, but any implementation needs to consider and handle those cases. |
I don't know why you think so, because to me,
This is handled AFAIK. Please check the test cases and let me know if you have more cases in mind. |
Zend/tests/type_declarations/intersection_types/implicit_nullable_intersection_type.phpt
Outdated
Show resolved
Hide resolved
0d9e382
to
014865b
Compare
014865b
to
e83f8db
Compare
Zend/zend_language_parser.y
Outdated
@@ -798,6 +798,7 @@ type_expr: | |||
| '?' type { $$ = $2; $$->attr |= ZEND_TYPE_NULLABLE; } | |||
| union_type { $$ = $1; } | |||
| intersection_type { $$ = $1; } | |||
| '?' intersection_type { $$ = $2; $$->attr |= ZEND_TYPE_NULLABLE; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding the nullability syntax. I find ?X&Y
, while technically unambiguous due to null&Y
not making sense, just isn't great for readability.
Further, we decided against ?X|Y
in the union types RFC, and I think that decision should hold (even though the reasons are somewhat different.
I've got an implementation for (X&Y)|null
, which is my preferred syntax at: https://gist.github.com/sgolemon/660b105e6894a6341792a479cda8f76b
However, we are much too late for 8.1 at this point and syntax is too important to rush, so this is going to have to wait for 8.2 no matter what we do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding the nullability syntax. I find ?X&Y, while technically unambiguous due to null&Y not making sense, just isn't great for readability.
Further, we decided against ?X|Y in the union types RFC, and I think that decision should hold (even though the reasons are somewhat different.
Agreed.
I've got an implementation for
(X&Y)|null
I'm not opposed to allowing parenthesis, but requiring them seems unnecessary - the precedence of &
/|
and &&
/||
is known in other contexts in php (operator precedence).
If (A&B)|null
was allowed, there'd be the question of whether (A)|null
should be allowed, (A)|(null)
, etc. It seems like it should (IF allowed), though the syntax seems less readable
However, we are much too late for 8.1 at this point and syntax is too important to rush, so this is going to have to wait for 8.2 no matter what we do.
Agreed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think you can use ?X|Y
being disallowed to conclude that everyone would also be against the special case of ?X&Y
. At the time in the Github discussion I argued against ?(X|Y)
, because it added parenthesis to not be ambiguous which would otherwise not be needed, and X|Y|null
was available as an alternative. In that case having a more complicated syntax only to somehow include ?
would have been counterproductive, in my opinion.
Yet I very much see the value of ?X&Y
- it enables optional parameters/properties, and it does not contain parenthesis. If combined union type and intersection type syntax ever makes it into PHP, it would be easy to not allow ?
there, just as ?
is not allowed for union types. So the syntax seems forward-compatible and geared towards a common use case in PHP.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If (A&B)|null was allowed, there'd be the question of whether (A)|null should be allowed, (A)|(null), etc. It seems like it should (IF allowed), though the syntax seems less readable
That's a fair complaint. For me it comes down to finding a balance between providing the functionality that's being asked for quite strongly, and not over-delivering syntax that hasn't been entirely thought through. That's why my version of this patch only allows null
on the right hand side, and requires parens around the intersection. It's the MOST restrictive syntax, and thereby the least likely to cause issues after we've spent more time thinking about it.
Which is why the RFC for intersection types is called "pure intersection types", and solves only that problem (intersection). Here, we are introducing partial union + intersection semantics around
In addition to that, @trowski makes it clear that readability is also messy. For instance, I would expect:
In both cases, the It's not a big deal to, for now:
|
Ok, when I glanced at the diff I expected to see more C code changes to handle LSP, but it seems the existing code handles it nicely.
Agreed. Any syntax choice here is going to have repercussions, so we can't be hasty. |
☝️☝️☝️ This ☝️☝️☝️ |
I'll mention that using scalar types in PHP 7 was less than optimal since they weren't nullable. For most of the code I maintain (both open source and commercial) it didn't make sense to bother with typing in php 7.0, instead we waited for nullable types in 7.1. I fear this case will be similar, especially since making the parameter nullable later will cause a bc break, while the change itself does not cause bc breaks. If we're all aware of this and decide that limited use cases and thus limited feedback is what we're going for in favour of consistent nullability across types, there's no problem. Otherwise I would bring up the point of moving intersection types to 8.2 with nullability. This would require significant discussion, which is why I'm only doing an informal check of opinion instead of asking on the mailing list. |
Thank you so much @sgolemon for that patch you provided in #7259 (comment) While I personally think ?X&Y is the most appropriate, I feel like using |null would gather a broader consensus. The attached patch now contains a second commit that changes the syntax to X&Y|null (PR description also updated.) Because operator precedence is known, the brackets are not needed and I'd prefer skipping them. Type expressions are already long enough.
I would kindly ask you to reconsider this. As @alcaeus just mentioned, PHP 7.0 was blatantly missing nullable types. Let's learn from history and recognize that having intersection types not nullable right away makes them way less interesting/useful. This feels like a bug from a feature completeness pov. ExtractExactly what the feature freeze period is for. Alternatively, we could move intersection types to 8.2, but that'd be a shame given that we're so close to having them complete. (( Apologies, I didn't mean to edit your comment, I meant to quote it and I evidently don't know how to github -- @sgolemon )) |
4d9b538
to
5bc9946
Compare
There doesn't really look like there is consensus on this, and tagging happens this afternoon. Since no consensus can be built in half a day, it looks like intersections will have to be deployed as they have been voted on while this is resolved. |
Adding default null value ( BC breaks were avoided back then by using default null value (and later prefixing types with |
Note that this"workaround" was only possible for parameters (and with the possibly undesired side effect of making them optional), not returns (e.g. https://3v4l.org/3CrX5#v7.0.0 ), so several return type declarations couldn't be added before 7.1 |
While I don't like eliding the parens, I'm not going to veto it on those grounds, but would you consider making parens optional? It wouldn't make the change to the parser massively larger...
It's not my call at the end of the day. The 8.1 RMs (@ramsey, @patrickallaert, @krakjoe) have the most sway at this point in the release. I would certainly reiterate that going slow only costs us a little time. Rushing has potentially much worse consequences. |
The least disruptive course of action seems to be for this detail to go through the normal RFC process, if voting on that closes before RC, we can just merge it. |
While at it: the current patch seems to allow Edit: OK, that's a deliberate choice |
The RFC is declined. I'm closing to let someone else free to take over at any time in the future. |
Putting my OSS time where my mouth is :)
RFC at https://wiki.php.net/rfc/nullable_intersection_types
PHP 8.1 intersection types should be nullable IMHO. They're going to be much less interesting otherwise.
See https://externals.io/message/115479 for background and discussion.
This reuses the existingUpdated to use?
prefix to make intersection types compatible withnull
as argument, property, and return value.X&Y|null
as I feel like that's going to gather a broader consensus.This allows writing:
The?
syntax is choosen because it is the least surprising one and because the code already handles it (eg when computing error messages, see tests.)On the implementation side, the nullable type is handled separately from union types. That's why the patch is trivial.
Please send me more test cases if you have weird situation in mind, I'd happily add them here.