Re: [RFC] Nullsafe calls
| From: | Andrea Faulds | Date: | Wed, 10 Dec 2014 17:19:56 +0000 |
| Subject: | Re: [RFC] Nullsafe calls | ||
| References: | 1 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-79529@lists.php.net to get a copy of this message | ||
> On 9 Dec 2014, at 23:07, Josh Watzman <jwatzman@fb.com> wrote:
>
> Hey internals! A useful feature that Hack picked up in the last few months are "nullsafe
> calls", a way of propagating failure forward in a series of chained method calls to the end of
> the whole computation, getting rid of a lot of the boilerplate in the middle. I think the feature
> would be a good one for PHP as well, so I'm submitting this RFC to add it -- you can see the
> RFC itself for a full discussion of the motivation for the feature, as well as the feature itself:
>
> https://wiki.php.net/rfc/nullsafe_calls
Hi again,
I was in favour of this, but upon further thought, I’m not sure I am. I remember I also initially
liked it in Hack and then lost interest.
First, how is this substantially different from catching an exception? With Nikita’s Exceptions in
the Engine RFC (https://wiki.php.net/rfc/engine_exceptions_for_php7), something like this would be
possible:
try {
return $foo->bar()->qux()->elePHPant()->dance();
} catch (EngineException $e) {
return NULL;
}
That would essentially do the same as what you’re proposing:
return $foo?->bar()?->qux()?->elePHPant()?->dance();
Are there many instances where there’d be a substantial benefit to using ?-> versus catching an
exception?
Second, not short-circuiting is rather unintuitive. I think most people would expect it to
short-circuit. Note that ?? and isset() short-circuit, so this would be inconsistent with existing
NULL-checking operators. So why, then, are you proposing that it should not short-circuit? Is there
some obscure case that this makes easier? If anything, I’d expect that short-circuiting is the
more useful behaviour. For example, take the following hypothetical line of code:
$elePHPantParty->danceClub?->addToDanceFloor($elePHPantPool->remove());
If we have the short-circuiting behaviour, then if $elePHPantParty->danceClub is NULL,
->addToDanceFloor isn’t called and an ElePHPant isn’t removed from $elePHPantPool. On the
other hand, if ->danceClub isn’t NULL, ->addToDanceFloor is called and an ElePHPant will be
removed from $elePHPantPool.
With the non-short-circuiting behaviour, this code would have to be longer, and you couldn’t use
?-> here. Instead, you’d have to write this:
if ($elePHPantParty->danceClub !== NULL) {
$elePHPantParty->danceClub->addToDanceFloor($elePHPantPool->remove());
}
It is, admittedly, a hypothetical scenario, but it does demonstrate why having it not short-circuit
is less useful. Are there any examples where short-circuiting is a problem?
Third, as has already been mentioned, this doesn’t support ?-> for properties, which is both
unintuitive (people will reasonably expect it to work) and makes it a lot less useful, because you
won’t always be dealing with method calls. While $foo?->bar()?->foobar() might work, what
about something like $foo?->bar?->foobar(), where one of the links in the chain is a property?
This is not at all an unlikely scenario.
Finally, this may encourage bad code. As someone helpfully pointed out in the reddit discussion
(http://redd.it/2ot15u), this encourages breaking the Law of Demeter, i.e. that objects should only
talk to their immediate friends. Usually, long chains of method calls across multiple objects are
not a good idea, yet the main benefit of this RFC is to reduce the boilerplate needed for that
scenario.
I am only one voice in this discussion, but I personally don’t really like this RFC.
Thanks!
--
Andrea Faulds
http://ajf.me/