[RFC] Nullsafe operator

php.internals

Ilija Tovilo

6 years ago
Hi internals I'd like to introduce another RFC I've been working on: https://wiki.php.net/rfc/nullsafe_operator It introduces the nullsafe operator ?-> that skips null values when calling functions and fetching properties. In contrast to the last few attempts this RFC includes full short circuiting. Let me know what you think. Ilija

Jordi Boggiano

6 years ago
On 02/06/2020 22:52, Ilija Tovilo wrote:
> It introduces the nullsafe operator ?-> that skips null values when > calling functions and fetching properties. In contrast to the last few > attempts this RFC includes full short circuiting. >
I like it a lot! Concise and clear RFC. From having used a similar feature in TypeScript I can say it is quite convenient, easy to get used to and makes for much leaner code. IMO not having it on array accesses isn't so bad as with arrays you can easily isset($deep['into']['the']['array']) in one go, while with objects and getters etc it tends to lead to much uglier and repetitive code like:     if ($foo && $foo->getBar() && $foo->getBar()->getBaz()) { ... } So yeah, +1 Best, Jordi
-- Jordi Boggiano @seldaek - https://seld.be

Nikita Popov

6 years ago
On Tue, Jun 2, 2020 at 10:53 PM Ilija Tovilo <tovilo.ilija@gmail.com> wrote:
> Hi internals > > I'd like to introduce another RFC I've been working on: > https://wiki.php.net/rfc/nullsafe_operator > > It introduces the nullsafe operator ?-> that skips null values when > calling functions and fetching properties. In contrast to the last few > attempts this RFC includes full short circuiting. > > Let me know what you think. >
The semantics look reasonable to me, but I'd recommend including some discussion on the rationale behind the short-circuiting behavior in the RFC. That is, what the options are, and why this is the best option (which is not the option that the previous RFC on this topic picked). It would also be nice to cross-reference semantics of ?-> in other languages that have it, to make sure we don't introduce any unexpected WTFs for people switching between languages. I *think* the specified behavior is consistent with what everyone else does, but I haven't checked to be sure. Regards, Nikita

Ilija Tovilo

6 years ago
Hi Nikita
>> I'd like to introduce another RFC I've been working on: >> https://wiki.php.net/rfc/nullsafe_operator > > The semantics look reasonable to me, but I'd recommend including some > discussion on the rationale behind the short-circuiting behavior in the > RFC. That is, what the options are, and why this is the best option (which > is not the option that the previous RFC on this topic picked). It would > also be nice to cross-reference semantics of ?-> in other languages that > have it, to make sure we don't introduce any unexpected WTFs for people > switching between languages. I think the specified behavior is consistent > with what everyone else does, but I haven't checked to be sure.
Thanks for your feedback. I added a short analysis of the most popular programming languages as well as a list of benefits and drawbacks of short circuiting. We might still go into detail on what the languages that do short circuiting consider part of the chain. If it doesn't clutter the RFC too much I will do that. Ilija

Peter Stalman

6 years ago
> Hi internals > > I'd like to introduce another RFC I've been working on: > https://wiki.php.net/rfc/nullsafe_operator > > It introduces the nullsafe operator ?-> that skips null values when > calling functions and fetching properties. In contrast to the last few > attempts this RFC includes full short circuiting. > > Let me know what you think. > > Ilija
Hi Internals, Wouldn't it make more sense to make `isset` smarter? So that it can handle these situations just like it would with array access. That way you could use the null coalescing operator as well. I don't see many situations where you would be selective in which method in the chain you would want to make nullsafe and which ones you wouldn't. I think it would mostly be the entire chain, in which case using `??` would be much less verbose. In the few cases where you want to be specific in which are nullsafe and which ones aren't you can introduce one more variable. Using the first example in the RFC this would visully be far nicer and more readable about the intent: $country = $session->user->getAddress()->country ?? null; Besides, shouldn't the example really be: $user->getAddressCountry(); I don't recall ever having to nest three levels like that example. I know the example is contrived, but wouldn't you know if you have a logged in user or not? Then just have a simple getter on the user for what you need to check. Chances are those variables you're trying to save will be used elsewhere, or if not, refactor. Also, assuming we have control over the User class, you can either make address a property or use the magic getters (that many frameworks have, love or hate them). Even the new new accepted Constructor Property Promotion would be helpful in facilitating that. Basically we can easily get around this problem already, and some frameworks do it by default. If not, writing one getter where you have to check a few things is IMO far nicer than a long chain of possibly null objects. This is how I would solve the issue, assuming we're just in the controller we don't make anything specifically for the User or Address classes and no other uses for those specifically are needed. protected function getCountry() { $user = $this->session->user ?? null; if ($user === null) $this->redirectToLogin(); if ($user->getAddress() === null) return null; return $user->getAddress()->country ?? null; } Chaining that many objects together that may or may not be null just seems so wrong to me. My concern is that we would start seeing `?->` far too often and it would promote some lazy habits, because people would add it "just in case". Personally I think it should be more explicit when we are null-checking, and since the `->` object access usually doesn't have spaces around it, it could "muddy the water". It reminds me too much of the proposed "unary null coalescing operator", which also reminds me of the error control operator. Maybe make the syntax `->@` to be more clear? Sorry if I come off a bit harsh, but I don't see the need for this as other solutions to this problem are more favourable IMHO. As much as it can be annoying sometimes, the `Call to a member function foo() on null` is a very useful error. Thanks, Peter

Ilija Tovilo

6 years ago
Hi Peter
> Wouldn't it make more sense to make `isset` smarter? So that it can > handle these situations just like it would with array access. That > way you could use the null coalescing operator as well.
Both of those are valid approaches. I do prefer the ?-> operator for two reasons. 1. ?? is more error prone (e.g. you won't get an error if a variable or property is undefined) 2. You can see immediately which sub-expressions can be null and which cannot (or rather must not) That is not to say that there aren't also benefits to ?? 1. No new syntax to learn 2. You can see more clearly where the short circuiting chain ends
> I don't see many situations where you would be selective in which > method in the chain you would want to make nullsafe and which ones you > wouldn't.
IMO you should only use ?-> exactly where you expect null values. Using ?? would ignore null (as well as undefined) everywhere in any sub-expression even if unexpected.
> I don't recall ever having to nest three levels like that example.
I agree. Take the example with a grain of salt. It's hard to come up with a relatable, meaningful, short example.
> Sorry if I come off a bit harsh, but I don't see the need for this as > other solutions to this problem are more favourable IMHO.
Not in the slightest. That's why it's called a "request for feedback" and not "request for praise", you're free to disagree :)
> As much as it can be annoying sometimes, the `Call to a member > function foo() on null` is a very useful error.
Absolutely. To clarify: The idea is not to sprinkle ?-> everywhere. Only use ?-> when null is an expected and acceptable value. Ilija

Ryan Jentzsch

6 years ago
BIG THUMBS UP for this feature. As was mentioned that TypeScript uses this and saves developers lots of time by avoiding nested null checking. I suggest in the RFC including a list of other languages that have this feature. On Tue, Jun 2, 2020, 2:53 PM Ilija Tovilo <tovilo.ilija@gmail.com> wrote:

Ilija Tovilo

6 years ago
Hi internals
> I'd like to introduce another RFC I've been working on: > https://wiki.php.net/rfc/nullsafe_operator
I've reworded some things and added more information on short circuiting. Functionality wise the RFC has remained the same. Since there was little negative feedback I'd like to put this feature to a vote in ~1 week. If you have any concerns or criticism please let me know in time. Ilija

Илья Сомов

6 years ago
> I've reworded some things and added more information on short > circuiting. Functionality wise the RFC has remained the same. > > Since there was little negative feedback I'd like to put this feature > to a vote in ~1 week. If you have any concerns or criticism please let > me know in time.
Just curious, do you plan on putting this to a vote in near time? The feature freeze is coming soon.

Ilija Tovilo

6 years ago
> Just curious, do you plan on putting this to a vote in near time? The > feature freeze is coming soon.
There's a remaining complication with references which I had limited time to work on. This doesn't technically need to be fixed to start the vote but if it can't be solved reasonably it would have to be described in the RFC which is why I'm hesitant. I'll invest some time over the next few days so that I can hopefully start the vote by the end of the week. If I can't find a solution I might delay the RFC for PHP 8.1. Ilija

Ilija Tovilo

6 years ago
Hi internals
>> https://wiki.php.net/rfc/nullsafe_operator > > There's a remaining complication with references which I had limited > time to work on. This doesn't technically need to be fixed to start > the vote but if it can't be solved reasonably it would have to be > described in the RFC which is why I'm hesitant.
I updated the RFC to disallow using the nullsafe operator in expressions passed by reference. This solves the last remaining (known) issue. If there are no objections I'd like to start the vote on Tuesday, 2020-07-14. Ilija

Ilija Tovilo

6 years ago
Hi internals
>> https://wiki.php.net/rfc/nullsafe_operator > > I updated the RFC to disallow using the nullsafe operator in > expressions passed by reference. This solves the last remaining > (known) issue. If there are no objections I'd like to start the vote > on Tuesday, 2020-07-14.
I have actually made one more change to the RFC. Trying to take the reference of a nullsafe chain is now always an error (at compile time when possible, otherwise at runtime). Because of this change I'll postpone the vote until tomorrow. Ilija

Ilija Tovilo

6 years ago
Hi internals
> https://wiki.php.net/rfc/nullsafe_operator
Unfortunately, we have found some new edge cases that are currently not handled. I will have to delay the vote again. Over the next day or two I will implement the changes and see if there are any other surprises. If there are, I will be delaying the RFC to PHP 8.1. Sorry :( Ilija

Ilija Tovilo

6 years ago
Hi internals
> > https://wiki.php.net/rfc/nullsafe_operator > > Unfortunately, we have found some new edge cases that are currently > not handled.
So, we've decided to completely disallow the nullsafe operator in write context. This means you can no longer use it on the left hand side of an assignment. This change was made mostly due to technical issues but some of the semantics were also not completely clear (e.g. do we always execute the right hand side? which order? etc). You can find a diff of the changes here: https://github.com/iluuu1994/nullsafe-operator-rfc/compare/5df9d041d2d202e5fab02b5881f2c4dc1fd9bcce...v1 I realize that it's very much last-minute but I will be opening the vote tomorrow unless there are any objections. This way we have a few days to merge before the feature freeze if the RFC is accepted. Ilija

Markus Fischer

6 years ago
Hi Ilija,
> > I'd like to introduce another RFC I've been working on: > https://wiki.php.net/rfc/nullsafe_operator > > It introduces the nullsafe operator ?-> that skips null values when > calling functions and fetching properties. In contrast to the last few > attempts this RFC includes full short circuiting.
Would this still work together with short-circuiting and the null coalesce operator? I just didn't see a clear example about this but also figured that could be a practical way to use this: ```php $country = $session?->user?->getAddress()?->country ?? 'defaultCountry'; ``` (hope the example is readable, my MUA insists on wrapping the lines) thanks, - Markus

Ilija Tovilo

6 years ago
Hi Markus
> > https://wiki.php.net/rfc/nullsafe_operator > > Would this still work together with short-circuiting and the null > coalesce operator? > > $country = $session?->user?->getAddress()?->country ?? 'defaultCountry';
Yes, your example will still work, this is solely about references :) Ilija

Markus Fischer

6 years ago
Hi, On 14.07.20 10:51, Ilija Tovilo wrote:
>> Would this still work together with short-circuiting and the null >> coalesce operator? >> >> $country = $session?->user?->getAddress()?->country ?? 'defaultCountry'; > > Yes, your example will still work, this is solely about references :)
Thanks for clarifying, that's fantastic :) - Markus

Björn Larsson

6 years ago
Den 2020-07-14 kl. 10:51, skrev Ilija Tovilo:
> Hi Markus > >>> https://wiki.php.net/rfc/nullsafe_operator >> Would this still work together with short-circuiting and the null >> coalesce operator? >> >> $country = $session?->user?->getAddress()?->country ?? 'defaultCountry'; > Yes, your example will still work, this is solely about references :) > > Ilija
When I see this I come to think about if this might have helped with upgrading to PHP 7 from PHP 5 due to the RFC: - https://wiki.php.net/rfc/counting_non_countables Like: $value = $countvalue?->count($countvalue); Even if I solved over 90% replacing count with empty there could be a few more places where this might prove handy. So +1 on this! r//Björn L