# [RFC] Nullsafe operator

- Thread: https://externals.io/message/110336
- Original archive: https://news-web.php.net/php.internals/110336
- Started by Ilija Tovilo on 2020-06-02T20:52:55+00:00
- Messages: 18
- RFC: Nullsafe operator (Implemented (PHP 8.0)) — https://externals.io/rfc/nullsafe_operator.md
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · RFCs at https://externals.io/rfc.md · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #110336 — Ilija Tovilo — 2020-06-02T20:52:55+00:00

URL: https://externals.io/message/110336#110336

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

---

## #110338 — Jordi Boggiano — 2020-06-03T06:24:47+00:00

URL: https://externals.io/message/110336#110338 · In reply to: #110336

> 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

---

## #110345 — Nikita Popov — 2020-06-03T10:02:18+00:00

URL: https://externals.io/message/110336#110345 · In reply to: #110336

> 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

---

## #110361 — Peter Stalman — 2020-06-04T10:00:40+00:00

URL: https://externals.io/message/110336#110361 · In reply to: #110336

> 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

---

## #110366 — Ryan Jentzsch — 2020-06-04T11:23:15+00:00

URL: https://externals.io/message/110336#110366 · In reply to: #110336

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.



> 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

---

## #110401 — Ilija Tovilo — 2020-06-06T17:09:24+00:00

URL: https://externals.io/message/110336#110401 · In reply to: #110345

Hi Nikita

> > […]
>
> 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

---

## #110402 — Ilija Tovilo — 2020-06-06T17:16:57+00:00

URL: https://externals.io/message/110336#110402 · In reply to: #110361

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

---

## #110508 — Ilija Tovilo — 2020-06-15T07:52:48+00:00

URL: https://externals.io/message/110336#110508 · In reply to: #110336

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

---

## #110877 — someniatko — 2020-07-08T09:03:44+00:00

URL: https://externals.io/message/110336#110877 · In reply to: #110508

> 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.

---

## #110878 — Ilija Tovilo — 2020-07-08T09:25:41+00:00

URL: https://externals.io/message/110336#110878 · In reply to: #110877

> 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

---

## #110964 — Ilija Tovilo — 2020-07-12T13:57:15+00:00

URL: https://externals.io/message/110336#110964 · In reply to: #110878

Hi internals

> > […]
>
> 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

---

## #110992 — Ilija Tovilo — 2020-07-14T08:35:36+00:00

URL: https://externals.io/message/110336#110992 · In reply to: #110964

Hi internals

> > […]
>
> 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

---

## #110993 — Markus Fischer — 2020-07-14T08:44:40+00:00

URL: https://externals.io/message/110336#110993 · In reply to: #110336

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

---

## #110994 — Ilija Tovilo — 2020-07-14T08:51:19+00:00

URL: https://externals.io/message/110336#110994 · In reply to: #110993

Hi Markus

> > […]
>
> 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

---

## #110997 — Markus Fischer — 2020-07-14T10:44:15+00:00

URL: https://externals.io/message/110336#110997 · In reply to: #110994

Hi,


> > […]
> 
> Yes, your example will still work, this is solely about references :)

Thanks for clarifying, that's fantastic :)

- Markus

---

## #111007 — bjorn.x.larsson@telia.com — 2020-07-14T21:32:12+00:00

URL: https://externals.io/message/110336#111007 · In reply to: #110994

Den 2020-07-14 kl. 10:51, skrev Ilija Tovilo:

> Hi Markus
>
> > […]
> 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

---

## #111011 — Ilija Tovilo — 2020-07-15T07:07:54+00:00

URL: https://externals.io/message/110336#111011 · In reply to: #110992

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

---

## #111041 — Ilija Tovilo — 2020-07-16T10:21:08+00:00

URL: https://externals.io/message/110336#111041 · In reply to: #111011

Hi internals

> > […]
>
> 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
