# [RFC] anti-coalescing-operator

- Thread: https://externals.io/message/107661
- Original archive: https://news-web.php.net/php.internals/107661
- Started by Ken Stanley on 2019-10-24T17:21:19+00:00
- Messages: 34
- Page 1 of 2: messages 1 to 25 (25 per page, add `?page=N` to the URL)
- Next page: https://externals.io/message/107661.md?page=2
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #107661 — Ken Stanley — 2019-10-24T17:21:19+00:00

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

Since PHP 7.0 brought forward the Null Coalescing Operator (??), writing
more succinct code for how to handle null values has been a blessing. But,
what about the inverse when you want to do something when a value is not
null? You're left with the traditional (and sometimes verbose) methods of
using if conditions or the full-blown ternary operator `$foo !== null ?
<something> : null;`.

I am here to gauge the interest of the community in having an
anti-coalescing operator that would execute code only if the condition is
not null, otherwise returning null in its stead. If this is not a wholly
terrible idea, I will -- as suggested -- then continue to create an
official RFC.

My initial thought process would be to use a similar syntax to the Null
Coalescing Operator (??), but to add negation: `$bar = $foo !??
$foo->getBar()`. I didn't want to use `!?` because then if anybody wanted
to add an anti-ternary operator (e.g., `!?:`) for falsey comparison, then
they'd have to get creative or use the three-character approach I am
already proposing. The purpose is simply to negate the existing behavior,
so at first glance I do not see any BC breakages or additional complexities
that haven't already been addressed - naturally, I could be wrong.

The driving use case, as hinted at in my above example, is if I have a
nullable object I only want to call a method on it if the object is not
null. Otherwise, default to the null value.

I am working through the RFC Howto [https://wiki.php.net/rfc/howto], and it
suggests that I ask for wiki karma for my account (897syudjhf) so that I
may create the RFC when appropriate.

Additionally, I have not [yet] found any existing precedence for
anti-coalescing; i.e., there does not seem to be an elegant counterpart to
COALESCE() in SQL. And, as they say, naming is hard. If
`anti-coalescing-operator` does not sit well with you all, I am open to
naming suggestions.

Thank you for your time,
Ken Stanley

---

## #107662 — Dan Ackroyd — 2019-10-24T17:33:39+00:00

URL: https://externals.io/message/107661#107662 · In reply to: #107661

>
> Since PHP 7.0 brought forward the Null Coalescing Operator (??), writing
> more succinct code for how to handle null values has been a blessing. But,
> what about the inverse when you want to do something when a value is not
> null?

Hi Ken,

It may help to give a real world example, rather than a metasyntactic
one, as I can't immediately see how this would be useful.

People have been expressing a concern over 'symbol soup' for similar
ideas. The null colalesce scenario happens frequently enough, that it
seemed to overcome the hurdle needed for acceptance. Again, giving a
real world example of what you currently need to do frequently might
help other people understand the need.

cheers
Dan

---

## #107663 — Stephen Reay — 2019-10-24T17:46:08+00:00

URL: https://externals.io/message/107661#107663 · In reply to: #107662

> 
> 
> > […]
> 
> Hi Ken,
> 
> It may help to give a real world example, rather than a metasyntactic
> one, as I can't immediately see how this would be useful.
> 
> People have been expressing a concern over 'symbol soup' for similar
> ideas. The null colalesce scenario happens frequently enough, that it
> seemed to overcome the hurdle needed for acceptance. Again, giving a
> real world example of what you currently need to do frequently might
> help other people understand the need.
> 
> cheers
> Dan
> 
> -- 
> 
> 
> 

Hi Ken,

This sounds like an alternative approach (for solving the same basic problem) to the nullsafe operator discussed a while back, no?
https://wiki.php.net/rfc/nullsafe_calls


Cheers
Stephen

---

## #107664 — Ken Stanley — 2019-10-24T17:56:58+00:00

URL: https://externals.io/message/107661#107664 · In reply to: #107663

On Thu, Oct 24, 2019 at 1:46 PM Stephen Reay <php-lists@koalephant.com>
wrote:

> Hi Ken,
>
> This sounds like an alternative approach (for solving the same basic
> problem) to the nullsafe operator discussed a while back, no?
> https://wiki.php.net/rfc/nullsafe_calls
>
>
> Cheers
> Stephen
>

Hi Stephen!

Yes, it would be similar if the object you're testing against is the same
object you want to call (e.g., $foo !?? $foo->getBar()). But, if the
variable is not an object, or it's just a test for another object, then the
nullsafe operator does not seem to address this situation (e.g., $userId
!?? $bar->getUser($userId())). In fact, I could see this RFC complimenting
the nullsafe operator: $userId !?? $bar->getUser($userId)?->getName().

Thank you,
Ken Stanley

PS. Dan, I am going to respond to your request for a code example; I am
taking my time so that I can give you and everyone else a good example. :)

---

## #107665 — Ken Stanley — 2019-10-24T18:59:12+00:00

URL: https://externals.io/message/107661#107665 · In reply to: #107662

> 
> > […]
> But,
> > […]
>
> Hi Ken,
>
> It may help to give a real world example, rather than a metasyntactic
> one, as I can't immediately see how this would be useful.
>
> People have been expressing a concern over 'symbol soup' for similar
> ideas. The null colalesce scenario happens frequently enough, that it
> seemed to overcome the hurdle needed for acceptance. Again, giving a
> real world example of what you currently need to do frequently might
> help other people understand the need.
>
> cheers
> Dan
>

Hi Dan,

After some thought, and searching through my existing code bases, I believe
I've come up with a decent code example to help demonstrate the usefulness
of the proposed anti-coalescing-operator:

Without !??:
<?php

class ExampleController
{
    /**
     * PATCH a User object.
     */
    public function saveAction(int $userId)
    {
        $user = $this->getUser($userId);

        if (isset($_SERVER['fname']) {
            $user->setName($_SERVER['fname']);
        }

        if (isset($_SERVER['lname']) {
            $user->setName($_SERVER['lname']);
        }

        if (isset($_SERVER['mname']) {
            $user->setName($_SERVER['mname']);
        }

        if (isset($_SERVER['phone']) {
            $user->setName($_SERVER['phone']);
        }

        if (isset($_SERVER['email']) {
            $user->setName($_SERVER['email']);
        }

        $this-saveUser($user);
    }
}

With !??:
<?php

class ExampleController
{
    /**
     * PATCH a User object.
     */
    public function saveAction(int $userId)
    {
        $user = $this->getUser($userId);

        $_SERVER['fname'] !?? $user->setName($_SERVER['fname']);
        $_SERVER['lname'] !?? $user->setName($_SERVER['lname']);
        $_SERVER['mname'] !?? $user->setName($_SERVER['mname']);
        $_SERVER['phone'] !?? $user->setName($_SERVER['phone']);
        $_SERVER['email'] !?? $user->setName($_SERVER['email']);

        $this-saveUser($user);
    }
}
Thank you,
Ken Stanley

---

## #107668 — Rowan Tommins — 2019-10-24T20:24:16+00:00

URL: https://externals.io/message/107661#107668 · In reply to: #107665

Hi Ken,

This is definitely an interesting idea, and when described as "the 
opposite of ??" the !?? syntax makes sense.

Looking at the example, though, the "negating" part becomes a bit confusing.

The verbose form reads naturally as a positive assertion - "if this is 
set, do this":
>          if (isset($_SERVER['fname']) {
>              $user->setName($_SERVER['fname']);
>          }


If we used the ?? operator, it would be a negative, "if this is not set, 
do this":

>          $_SERVER['fname'] ?? $user->unsetName();

So the short-hand form becomes a kind of double negative - "if this is 
not set, don't do this", or "if this is not not set, do this":

>          $_SERVER['fname'] !?? $user->setName($_SERVER['fname']);


That makes me think that the choice of syntax isn't quite right, but I'm 
not sure what to suggest instead.


Regards,

-- 
Rowan Tommins (né Collins)
[IMSoP]

---

## #107669 — Andreas Hennings — 2019-10-24T20:29:15+00:00

URL: https://externals.io/message/107661#107669 · In reply to: #107665

>
> 
>
> > […]
>
> Hi Dan,
>
> After some thought, and searching through my existing code bases, I believe
> I've come up with a decent code example to help demonstrate the usefulness
> of the proposed anti-coalescing-operator:
>
> Without !??:
> <?php
>
> class ExampleController
> {
>     /**
>      * PATCH a User object.
>      */
>     public function saveAction(int $userId)
>     {
>         $user = $this->getUser($userId);
>
>         if (isset($_SERVER['fname']) {
>             $user->setName($_SERVER['fname']);
>         }
>
>         if (isset($_SERVER['lname']) {
>             $user->setName($_SERVER['lname']);
>         }
>
>         if (isset($_SERVER['mname']) {
>             $user->setName($_SERVER['mname']);
>         }
>
>         if (isset($_SERVER['phone']) {
>             $user->setName($_SERVER['phone']);
>         }
>
>         if (isset($_SERVER['email']) {
>             $user->setName($_SERVER['email']);
>         }
>
>         $this-saveUser($user);
>     }
> }
>
> With !??:
> <?php
>
> class ExampleController
> {
>     /**
>      * PATCH a User object.
>      */
>     public function saveAction(int $userId)
>     {
>         $user = $this->getUser($userId);
>
>         $_SERVER['fname'] !?? $user->setName($_SERVER['fname']);
>         $_SERVER['lname'] !?? $user->setName($_SERVER['lname']);
>         $_SERVER['mname'] !?? $user->setName($_SERVER['mname']);
>         $_SERVER['phone'] !?? $user->setName($_SERVER['phone']);
>         $_SERVER['email'] !?? $user->setName($_SERVER['email']);
>
>         $this-saveUser($user);
>     }
> }
> Thank you,
> Ken Stanley

Not convinced.
1. Most of the perceived brevity is from omitting line breaks and
curly brackets, which is a bit misleading imo.
2. It is not the intended use of these kinds of operators (ternary or
null coalesce). Normally you would use them to produce a value, here
you use them for control flow only.
3. One purpose of the operator should be that you don't have to repeat
the variable. Here you do, e.g. $_SERVER['fname']

1.
If you would simply omit the line breaks in the first version, you
would get this:

    if (isset($_SERVER['fname'])) $user->setName($_SERVER['fname']);
    if (isset($_SERVER['lname'])) $user->setName($_SERVER['lname']);
    if (isset($_SERVER['mname'])) $user->setName($_SERVER['mname']);
    if (isset($_SERVER['phone'])) $user->setName($_SERVER['phone']);
    if (isset($_SERVER['email'])) $user->setName($_SERVER['email']);

2.
Instead of "abusing" your new operator, you could simply "abuse" the
old ternary ?: instead:

    !isset($_SERVER['fname']) ?: $user->setName($_SERVER['fname']);
    !isset($_SERVER['lname']) ?: $user->setName($_SERVER['lname']);
    !isset($_SERVER['mname']) ?: $user->setName($_SERVER['mname']);
    !isset($_SERVER['phone']) ?: $user->setName($_SERVER['phone']);
    !isset($_SERVER['email']) ?: $user->setName($_SERVER['email']);

3.
One way to not repeat the variable would be to introduce a temporary
local variable, like so:

    if (NULL !== $fname = $_SERVER['fname'] ?? NULL) $user->setName($fname);

This gets more useful if the variable expression is something longer.

A new language feature for this purpose could have an anatomy like this:
https://3v4l.org/TjuuO or
https://3v4l.org/U6arm

and the short syntax would be like so:

   $product = ($x ??! NULL) * ($y ??! NULL);

or the `NULL` can be omitted:

   $product = ($x ??!) * ($y ??!);

So, the operator would break out of the current expression context,
and produce a value one level up, a bit like a try/throw/catch would,
or like a break in switch.

This is just a basic idea, it still leaves a lot of questions open.
If the expression context is multiple levels deep, how many of these
levels are we breaking?

I am not suggesting this is a good idea, but I think it is an
improvement to the original proposal.

-- Andreas

---

## #107670 — Kosit Supanyo — 2019-10-24T21:19:49+00:00

URL: https://externals.io/message/107661#107670 · In reply to: #107669

Hi Ken

I totally agree with Andreas especially:

One purpose of the operator should be that you don't have to repeat
> the variable. Here you do, e.g. $_SERVER['fname']


But if this operator provide some way not to repeat the variable it will
make sense. For example:

$_SERVER['fname'] !??  $user->setName($$)

But I think this functionality should be of something like pipeline
operator:

// send tmp variable to the next expression unconditionally
$ret = $_SERVER['fname'] |>  $user->setName($$);
// send tmp variable to the next expression only when $_SERVER['fname'] is
set.
$ret = $_SERVER['fname'] ?|>  $user->setName($$);

Also the syntax like above will be consistent with the proposed
safe-navigation operators.

Cheers

On Fri, Oct 25, 2019 at 3:29 AM Andreas Hennings <andreas@dqxtech.net>
wrote:

> 
> > […]
> wrote:
> > […]
> writing
> > […]
> not
> > […]
> believe
> > […]
> usefulness
> > […]
>
> Not convinced.
> 1. Most of the perceived brevity is from omitting line breaks and
> curly brackets, which is a bit misleading imo.
> 2. It is not the intended use of these kinds of operators (ternary or
> null coalesce). Normally you would use them to produce a value, here
> you use them for control flow only.
> 3. One purpose of the operator should be that you don't have to repeat
> the variable. Here you do, e.g. $_SERVER['fname']
>
> 1.
> If you would simply omit the line breaks in the first version, you
> would get this:
>
>     if (isset($_SERVER['fname'])) $user->setName($_SERVER['fname']);
>     if (isset($_SERVER['lname'])) $user->setName($_SERVER['lname']);
>     if (isset($_SERVER['mname'])) $user->setName($_SERVER['mname']);
>     if (isset($_SERVER['phone'])) $user->setName($_SERVER['phone']);
>     if (isset($_SERVER['email'])) $user->setName($_SERVER['email']);
>
> 2.
> Instead of "abusing" your new operator, you could simply "abuse" the
> old ternary ?: instead:
>
>     !isset($_SERVER['fname']) ?: $user->setName($_SERVER['fname']);
>     !isset($_SERVER['lname']) ?: $user->setName($_SERVER['lname']);
>     !isset($_SERVER['mname']) ?: $user->setName($_SERVER['mname']);
>     !isset($_SERVER['phone']) ?: $user->setName($_SERVER['phone']);
>     !isset($_SERVER['email']) ?: $user->setName($_SERVER['email']);
>
> 3.
> One way to not repeat the variable would be to introduce a temporary
> local variable, like so:
>
>     if (NULL !== $fname = $_SERVER['fname'] ?? NULL)
> $user->setName($fname);
>
> This gets more useful if the variable expression is something longer.
>
> A new language feature for this purpose could have an anatomy like this:
> https://3v4l.org/TjuuO or
> https://3v4l.org/U6arm
>
> and the short syntax would be like so:
>
>    $product = ($x ??! NULL) * ($y ??! NULL);
>
> or the `NULL` can be omitted:
>
>    $product = ($x ??!) * ($y ??!);
>
> So, the operator would break out of the current expression context,
> and produce a value one level up, a bit like a try/throw/catch would,
> or like a break in switch.
>
> This is just a basic idea, it still leaves a lot of questions open.
> If the expression context is multiple levels deep, how many of these
> levels are we breaking?
>
> I am not suggesting this is a good idea, but I think it is an
> improvement to the original proposal.
>
> -- Andreas

---

## #107671 — Bruce Weirdan — 2019-10-24T21:23:59+00:00

URL: https://externals.io/message/107661#107671 · In reply to: #107665

Hi Ken

>         $_SERVER['fname'] !?? $user->setName($_SERVER['fname']);
>         $_SERVER['lname'] !?? $user->setName($_SERVER['lname']);
>         $_SERVER['mname'] !?? $user->setName($_SERVER['mname']);
>         $_SERVER['phone'] !?? $user->setName($_SERVER['phone']);
>         $_SERVER['email'] !?? $user->setName($_SERVER['email']);

What you described is already achievable with short-circuit && :

  isset($_SERVER['fname']) && $user->setName($_SERVER['fname']);

Besides, it's a widely used idiom known from shell scripting.

-- 
  Best regards,
      Bruce Weirdan                                     mailto:weirdan@gmail.com

---

## #107672 — Kosit Supanyo — 2019-10-24T21:30:36+00:00

URL: https://externals.io/message/107661#107672 · In reply to: #107671

Hi Bruce

If I understand correctly.

$_SERVER['fname'] !?? $user->setName($_SERVER['fname']);


Will return the result of  $user->setName($_SERVER['fname']) if
$_SERVER['fname']  is set or null if not set. While:

isset($_SERVER['fname']) && $user->setName($_SERVER['fname']);


Will return boolean.

Cheers



> Hi Ken
>
> > […]
>
> What you described is already achievable with short-circuit && :
>
>   isset($_SERVER['fname']) && $user->setName($_SERVER['fname']);
>
> Besides, it's a widely used idiom known from shell scripting.
>
> --
>   Best regards,
>       Bruce Weirdan                                     mailto:
> weirdan@gmail.com

---

## #107673 — Ken Stanley — 2019-10-24T21:48:53+00:00

URL: https://externals.io/message/107661#107673 · In reply to: #107669

On Thu, Oct 24, 2019 at 4:29 PM Andreas Hennings <andreas@dqxtech.net>
wrote:

> 
> > […]
> wrote:
> > […]
> writing
> > […]
> not
> > […]
> believe
> > […]
> usefulness
> > […]
>
> Not convinced.
> 1. Most of the perceived brevity is from omitting line breaks and
> curly brackets, which is a bit misleading imo.


This argument can be made about ?? And ?:, which have already passed muster
and creates a precedent. Additionally, this is meant to compliment the
existing ?? by adding a negation counterpart (similar to how == has !== and
> has <).

I’m curious to what you find misleading about it? Its meant to literally be
the not-null coalescing operator.


> 2. It is not the intended use of these kinds of operators (ternary or
> null coalesce). Normally you would use them to produce a value, here
> you use them for control flow only.


Here is another example, not using them for flow control:

<?php

class Foo
{
    /**
     * @return User|null
     */
    private $user;

    /**
     * @return string|null
     */
    public function getName(): ?string
    {
        return $this->user !?? $this->user->getName();
    }
}

compared to:
<?php

class Foo
{
    /**
     * @return User|null
     */
    private $user;

    /**
     * @return string|null
     */
    public function getName(): ?string
    {
        // or $this->user instanceof User
        return $this->user !== null ? $this->user->getName() : null;
    }
}


> 3. One purpose of the operator should be that you don't have to repeat
> the variable. Here you do, e.g. $_SERVER['fname']
>
>
I'm not sure how that's necessarily a bad thing. Would you elaborate? Is it
simply a matter of writing the same characters twice? How is that different
than:

if (isset($_SERVER['fname'])) {
    $user->setName($_SERVER['fname']);
}


> 1.
> If you would simply omit the line breaks in the first version, you
> would get this:
>
>     if (isset($_SERVER['fname'])) $user->setName($_SERVER['fname']);
>     if (isset($_SERVER['lname'])) $user->setName($_SERVER['lname']);
>     if (isset($_SERVER['mname'])) $user->setName($_SERVER['mname']);
>     if (isset($_SERVER['phone'])) $user->setName($_SERVER['phone']);
>     if (isset($_SERVER['email'])) $user->setName($_SERVER['email']);


Ugh! I just noticed that I mistakenly did not update the method names for
each line, so I can see how this might look like flow control. Those
methods should be setFirstName, setLastName, setMiddleName, setPhone, and
setEmail respectively. My apologies.


>
> 2.
> Instead of "abusing" your new operator, you could simply "abuse" the
> old ternary ?: instead:
>
>     !isset($_SERVER['fname']) ?: $user->setName($_SERVER['fname']);
>     !isset($_SERVER['lname']) ?: $user->setName($_SERVER['lname']);
>     !isset($_SERVER['mname']) ?: $user->setName($_SERVER['mname']);
>     !isset($_SERVER['phone']) ?: $user->setName($_SERVER['phone']);
>     !isset($_SERVER['email']) ?: $user->setName($_SERVER['email']);
>
>
Re; #1 and #2 here: the same argument can be made for both ?? and ?:, which
again, has already passed muster and set precedent.


> 3.
> One way to not repeat the variable would be to introduce a temporary
> local variable, like so:
>
>     if (NULL !== $fname = $_SERVER['fname'] ?? NULL)
> $user->setName($fname);
>
The entire point of !?? would be to keep things terse and simple in nature.
Does it fit every possible use case? No. But neither do ?? and ?:. And,
like ?? and ?:, no one is required to use it if they feel being more
verbose makes sense for their needs.


>
> This gets more useful if the variable expression is something longer.
>
> A new language feature for this purpose could have an anatomy like this:
> https://3v4l.org/TjuuO or
> https://3v4l.org/U6arm
>
> and the short syntax would be like so:
>
>    $product = ($x ??! NULL) * ($y ??! NULL);
>
> or the `NULL` can be omitted:
>
>    $product = ($x ??!) * ($y ??!);
>

Not sure if the ??! was on purpose as an alternative to !??, but given how
other operators put the negation operator first, I feel we should maintain
the common standard.


>
> So, the operator would break out of the current expression context,
> and produce a value one level up, a bit like a try/throw/catch would,
> or like a break in switch.
>
>
Isn't this the same as the aforementioned null-safe operator [
https://wiki.php.net/rfc/nullsafe_calls]?


> This is just a basic idea, it still leaves a lot of questions open.
> If the expression context is multiple levels deep, how many of these
> levels are we breaking?
>
> I am not suggesting this is a good idea, but I think it is an
> improvement to the original proposal.
>
> -- Andreas
>


Thank you for the great feedback!

---

## #107674 — Ken Stanley — 2019-10-24T21:52:54+00:00

URL: https://externals.io/message/107661#107674 · In reply to: #107670

On Thu, Oct 24, 2019 at 5:19 PM Kosit Supanyo <webdevxp.com@gmail.com>
wrote:

> Hi Ken
>
> I totally agree with Andreas especially:
>
> One purpose of the operator should be that you don't have to repeat
> > […]
>
>
> But if this operator provide some way not to repeat the variable it will
> make sense. For example:
>
> $_SERVER['fname'] !??  $user->setName($$)
>

I asked Andreas for their opinion on why this is bad in this context?
Especially since if I were to use a traditional ternary or if condition,
then I'd still be repeating the variable.


>
> But I think this functionality should be of something like pipeline
> operator:
>
> // send tmp variable to the next expression unconditionally
> $ret = $_SERVER['fname'] |>  $user->setName($$);
> // send tmp variable to the next expression only when $_SERVER['fname'] is
> set.
> $ret = $_SERVER['fname'] ?|>  $user->setName($$);
>
> Also the syntax like above will be consistent with the proposed
> safe-navigation operators.
>

I'm more interested in having a negation operator for the null-coalescing
operator, especially since cognatively it should be easy to discern what it
does. I've personally not seen |>, and I'd be confused as to what it does
(e.g., is it a bitwise OR on a greater than comparison?).

Thank you! The idea of $$ is neat, but not quite what I'm trying to achieve
here. If anything, wouldn't that facilitate a different RFC?

- Ken Stanley

---

## #107675 — Ken Stanley — 2019-10-24T21:55:31+00:00

URL: https://externals.io/message/107661#107675 · In reply to: #107672

On Thu, Oct 24, 2019 at 5:31 PM Kosit Supanyo <webdevxp.com@gmail.com>
wrote:

> Hi Bruce
>
> If I understand correctly.
>
> $_SERVER['fname'] !?? $user->setName($_SERVER['fname']);
>
>
> Will return the result of  $user->setName($_SERVER['fname']) if
> $_SERVER['fname']  is set or null if not set. While:
>
> isset($_SERVER['fname']) && $user->setName($_SERVER['fname']);
>
>
> Will return boolean.
>

Yes. Semantically the same, but one is terse and the other is explicit.


>
> Cheers

---

## #107676 — Mark Randall — 2019-10-24T22:00:55+00:00

URL: https://externals.io/message/107661#107676 · In reply to: #107674

> I'm more interested in having a negation operator for the null-coalescing
> operator, especially since cognatively it should be easy to discern what it
> does.

At the point your syntax ends up looking like you're screaming at your 
source code, I think easy cognition has likely gone out the window.

There are plenty of much more expressive ways of doing this without 
introducing new syntax IMHO.

Mark Randall

---

## #107677 — Kosit Supanyo — 2019-10-24T22:02:52+00:00

URL: https://externals.io/message/107661#107677 · In reply to: #107674

Hi Ken

`|>` is not something new it appeared in many languages long time ago (in
some forms). JavaScript also has a proposal of it. And PHP someone has
already proposed one.
https://github.com/tc39/proposal-pipeline-operator
https://wiki.php.net/rfc/pipe-operator

Cheers



>
> On Thu, Oct 24, 2019 at 5:19 PM Kosit Supanyo <webdevxp.com@gmail.com>
> wrote:
>
> > […]
>
> I asked Andreas for their opinion on why this is bad in this context?
> Especially since if I were to use a traditional ternary or if condition,
> then I'd still be repeating the variable.
>
>
> > […]
>
> I'm more interested in having a negation operator for the null-coalescing
> operator, especially since cognatively it should be easy to discern what it
> does. I've personally not seen |>, and I'd be confused as to what it does
> (e.g., is it a bitwise OR on a greater than comparison?).
>
> Thank you! The idea of $$ is neat, but not quite what I'm trying to
> achieve here. If anything, wouldn't that facilitate a different RFC?
>
> - Ken Stanley

---

## #107679 — Ken Stanley — 2019-10-24T22:49:28+00:00

URL: https://externals.io/message/107661#107679

> 
> > […]
> it
> > […]
>
> At the point your syntax ends up looking like you're screaming at your
> source code, I think easy cognition has likely gone out the window.
>
> There are plenty of much more expressive ways of doing this without
> introducing new syntax IMHO.


Mark,

Yes, the operator would be new as in it doesn’t exist, but it’s not new in
the fact that it is simply a negation of an existing operator.

I would be keen to see the more expressive techniques that retain the
succinctness of having a not-null coalescing operator.

I can certainly appreciate the hesitation to introduce more syntax.
However, I am arguing that this particular case is merely an extension
(compliment) of the existing null-coalescing operator and therefore it’s
not truly new; especially since !== null is a very common comparison used
in programming.


>
> Mark Randall
>
> --
> 
> 


Thank you.

> `|>` is not something new it appeared in many languages long time ago (in
some forms). JavaScript also has a proposal of it. And PHP someone has
already proposed one.
> https://github.com/tc39/proposal-pipeline-operator
> https://wiki.php.net/rfc/pipe-operator

Kosit,

Thank you. In this case I’d still argue that my proposed operator, for what
I’m intending it to be, is the better solution.

I appreciate that my example might not have been the best, but I wanted to
demonstrate one possible usage out of many that could be used to easily
solve the same problem of needing to do “something” based on a non-null
value.

Thank you!
-- 
"Do not go gentle into that good night. Rage, rage against the dying of the
light." — Dylan Thomas

---

## #107680 — Sara Golemon — 2019-10-24T23:23:52+00:00

URL: https://externals.io/message/107661#107680 · In reply to: #107675

> > […]
>
> Just testing the waters: Is there any appetite to have AND and OR behave
more like Pythons operator?
Instead of now:
(a or b) => bool(true) if either of a or b are true
(a and b) =>  bool(true) is either of a or b are true

Behave as:
(a or b) => Value of a if true, b if a is not true but b is, bool(false)
otherwise.
(a and b) => Value of b if both are true, bool(false) otherwise.

Coincidentally, this change to `T_LOGICAL_AND` would server OP's purpose.

I'll tell ya, I'm leaning "No" because BC, but at the same time, AND/OR
seem to be underutilized constructs and I *suspect* (having done zero
research), that most existing uses would yield the same result as they do
now.

-Sara

---

## #107681 — Sara Golemon — 2019-10-24T23:28:01+00:00

URL: https://externals.io/message/107661#107681 · In reply to: #107663

On Thu, Oct 24, 2019 at 12:46 PM Stephen Reay <php-lists@koalephant.com>
wrote:

> This sounds like an alternative approach (for solving the same basic
> problem) to the nullsafe operator discussed a while back, no?

https://wiki.php.net/rfc/nullsafe_calls
>
> At the risk of hijacking, @matthewrask asked me about ?-> a couple weeks
ago (Javascript is making this one popular), and I threw together a rough
PoC at
https://github.com/php/php-src/compare/master...sgolemon:null-coalesce which
I suspect he intends to RFC properly soon.  As long as the topic is at
hand, what's the general appetite for it?  Should I bother polishing the
turd?

-Sara

---

## #107682 — Andreas Hennings — 2019-10-25T00:00:46+00:00

URL: https://externals.io/message/107661#107682 · In reply to: #107680

>
> 
>
> > […]
> more like Pythons operator?

Similar to javascript || and &&, although not exactly the same.

> Instead of now:
> (a or b) => bool(true) if either of a or b are true
> (a and b) =>  bool(true) is either of a or b are true
>
> Behave as:
> (a or b) => Value of a if true, b if a is not true but b is, bool(false)
> otherwise.
> (a and b) => Value of b if both are true, bool(false) otherwise.
>
> Coincidentally, this change to `T_LOGICAL_AND` would server OP's purpose.
>
> I'll tell ya, I'm leaning "No" because BC, but at the same time, AND/OR
> seem to be underutilized constructs and I *suspect* (having done zero
> research), that most existing uses would yield the same result as they do
> now.

At one point I started using these operators because they have
different operator precedence than || and &&, allowing assignment in
conditions without parentheses.
I gave up on this only to comply with coding standards and to not
confuse people.
I would think we will make a lot of people angry if we change this.
Imo, let's not.

Besides, a lot of this can be achieved with the ?: ternary shortcut
(not sure what's the name).

> (a or b) => Value of a if true, b if a is not true but b is, bool(false)
$a ?: ($b ?: false) === ($a ?: $b) ?: false === $a ?: $b ?: false

> (a and b) => Value of b if both are true, bool(false) otherwise.
$a ? ($b ?: false) : false === $a ? $b ?: false : false

https://3v4l.org/q8Al9

It is a bit more verbose, I admit. But in most cases we don't need to
replicate the exact behavior, and a simple ?: will do the trick.

-- Andreas

>
> -Sara

---

## #107683 — Andreas Hennings — 2019-10-25T00:03:21+00:00

URL: https://externals.io/message/107661#107683 · In reply to: #107681

>
> On Thu, Oct 24, 2019 at 12:46 PM Stephen Reay <php-lists@koalephant.com>
> wrote:
>
> > […]
>
> https://wiki.php.net/rfc/nullsafe_calls
> > […]
> ago (Javascript is making this one popular), and I threw together a rough
> PoC at
> https://github.com/php/php-src/compare/master...sgolemon:null-coalesce which
> I suspect he intends to RFC properly soon.  As long as the topic is at
> hand, what's the general appetite for it?  Should I bother polishing the
> turd?
>
> -Sara

?-> is a great idea.

The problem is this only works for method chaining, not for function
argument nesting.
So we might want something else in addition to that.

foo(bar(baz() ???) ???);

-- Andreas

---

## #107684 — Andreas Hennings — 2019-10-25T00:27:05+00:00

URL: https://externals.io/message/107661#107684 · In reply to: #107673

>
> 
> > […]
>
>
> This argument can be made about ?? And ?:, which have already passed muster and creates a precedent.

But these were designed to produce a value, not for just control flow
- see my other point.
Yes, the same argument could have been made for those, if a similar
example had been given to advertise their introduction.

> Additionally, this is meant to compliment the existing ?? by adding a negation counterpart (similar to how == has !== and > has <).
>
> I’m curious to what you find misleading about it? Its meant to literally be the not-null coalescing operator.

Misleading as in "look how much shorter this is".

>
> > […]
>
>
> Here is another example, not using them for flow control:
>
> <?php
>
> class Foo
> {
>     /**
>      * @return User|null
>      */
>     private $user;
>
>     /**
>      * @return string|null
>      */
>     public function getName(): ?string
>     {
>         return $this->user !?? $this->user->getName();
>     }
> }
>
> compared to:
> <?php
>
> class Foo
> {
>     /**
>      * @return User|null
>      */
>     private $user;
>
>     /**
>      * @return string|null
>      */
>     public function getName(): ?string
>     {
>         // or $this->user instanceof User
>         return $this->user !== null ? $this->user->getName() : null;
>     }
> }

This example is better indeed.
But here I would prefer to have the ?-> operator proposed earlier
(nullsafe calls).

         return $this->user?->getName();

> > […]
>
> I'm not sure how that's necessarily a bad thing. Would you elaborate? Is it simply a matter of writing the same characters twice? How is that different than:
>
> if (isset($_SERVER['fname'])) {
>     $user->setName($_SERVER['fname']);
> }

I thought you like brevity? "terse and simple"?
Ofc it is not just about typing more characters, but about having two
places that need to be updated if we change the value expression.
All the arguments for DRY apply.

And yes, with existing if/else code we would also have this kind of
repetition for this use case.
But if we introduce a new operator, we would expect this to go away,
wouldn't we?

The repetition becomes more relevant if the expression we would repeat
is really long:

isset($something['something']['something']['something']) !??
$something['something']['something']['something']->foo();

>
> > […]
>
>
> Ugh! I just noticed that I mistakenly did not update the method names for each line, so I can see how this might look like flow control. Those methods should be setFirstName, setLastName, setMiddleName, setPhone, and setEmail respectively. My apologies.

I meant "only control flow" in the sense that we are not returning a
value, or rather, we do not read the value.
Ofc it makes a more lively example to have different methods, but I
was looking past that already :)

>
> > […]
>
> Re; #1 and #2 here: the same argument can be made for both ?? and ?:, which again, has already passed muster and set precedent.
>

As before, they were not really designed for this case.
But if we do use them, they already go a long way.

> > […]
>
> The entire point of !?? would be to keep things terse and simple in nature. Does it fit every possible use case? No. But neither do ?? and ?:. And, like ?? and ?:, no one is required to use it if they feel being more verbose makes sense for their needs.
>
> > […]
>
>
> Not sure if the ??! was on purpose as an alternative to !??, but given how other operators put the negation operator first, I feel we should maintain the common standard.

I don't really think of it as a "negated ??". The motivation to have a
negation seems quite theoretical to me.
I am more interested in actual use cases.
>
> > […]
>
> Isn't this the same as the aforementioned null-safe operator [https://wiki.php.net/rfc/nullsafe_calls]?

Except that ?-> only works for method chaining, not for function args.
(as pointed out in a previous message)

-- Andreas

>
> > […]
>
>
>
> Thank you for the great feedback!

---

## #107685 — Mike Schinkel — 2019-10-25T00:43:53+00:00

URL: https://externals.io/message/107661#107685 · In reply to: #107683

> 
> 
> 
> > […]
> 
> ?-> is a great idea.

Totally agree, that would be nice.

> The problem is this only works for method chaining, not for function
> argument nesting.
> So we might want something else in addition to that.
> 
> foo(bar(baz() ???) ???);

I am confused about this.  Why would this be needed?  In case the functions baz(), bar() or foo() do not exist?

Please help me see what I am missing.


-Mike

---

## #107686 — Mike Schinkel — 2019-10-25T00:54:31+00:00

URL: https://externals.io/message/107661#107686 · In reply to: #107679

> 
> I would be keen to see the more expressive techniques that retain the
> succinctness of having a not-null coalescing operator.


When I read your first example, I immediately thought I would handle your example in this way:

$user->setFName( $_SERVER[ 'fname' ] ?? null );
$user->setLName( $_SERVER[ 'lname' ] ?? null );
$user->setMName( $_SERVER[ 'mname' ] ?? null );
$user->setPhone( $_SERVER[ 'phone' ] ?? null );
$user->setEmail( $_SERVER[ 'email' ] ?? null );

Admittedly it does not require the functionality of your proposed operator, and it delegates the null handling to the set*() methods, but it is more succinct and does not require duplicating `$_SERVER[ '*' ]`, so it would be a winner for me. 

I also do not mind putting more effort into writing functions if it means less effort required to call the functions. But maybe that is just me?

Your 2nd example was more compelling for me, but Sara's nullsafe calls RFC uses a syntax that is more clear and obvious to me.

Is there a 3rd or 4th use-case you have that are unlike the first two?

-Mike

---

## #107687 — Ken Stanley — 2019-10-25T02:31:04+00:00

URL: https://externals.io/message/107661#107687 · In reply to: #107686

> 
> I would be keen to see the more expressive techniques that retain the
> succinctness of having a not-null coalescing operator.
>
>
>
> When I read your first example, I immediately thought I would handle your
> example in this way:
>
> $user->setFName( $_SERVER[ 'fname' ] ?? null );
>
> $user->setLName( $_SERVER[ 'lname' ] ?? null );
>
> $user->setMName( $_SERVER[ 'mname' ] ?? null );
>
> $user->setPhone( $_SERVER[ 'phone' ] ?? null );
>
> $user->setEmail( $_SERVER[ 'email' ] ?? null );
>
>
> Admittedly it does not require the functionality of your proposed
> operator, and it delegates the null handling to the set*() methods, but it
> is more succinct and does not require duplicating `$_SERVER[ '*' ]`, so
> it would be a winner for me.
>
>
The problem here is that null values may or may not be valid inputs for the
setters. Assuming for one moment that the setters do allow null, what does
that mean for the underlying model? Is null to mean that it’s under? Or is
null just another possible value?

Using !?? to only call a setter if there is a non-null value is very
important in many circumstances - my original example was to illustrate a
succinct way to implement a REST PATCH HTTP request, where only fields with
values get updated - in other words, you don’t want to set other fields to
null because you want to retain their original values; not overwrite them.
Overwriting values with null is a valid use case, but not for this operator
(not necessarily).

Null means nothing, no value, or better: not answered. This is distinctly
different than ‘’, false, or 0. Those are explicit responses to a question.
Null Just means no data.


> I also do not mind putting more effort into writing functions if it means
> less effort required to call the functions. But maybe that is just me?
>
>
But if you don’t have to, then why would you? I’m all for clarity and
expressiveness. But I’m also for simplicity and being as succinct as
practically possible.


> Your 2nd example was more compelling for me, but Sara's nullsafe calls RFC
> uses a syntax that is more clear and obvious to me.
>
>
I am a Symfony developer, and as such I like to utilize annotations (bear
with me). They have a ParamConverter annotation that can automatically look
up an entity based on the type hint given to a controller action.

If the parameter is null able, I may need to add an if condition to look up
a sane default value when the parameter comes through as null. It would be
much more succinct (and less error prone) to be able to say something like

/**
 * @ParamConverter(name=“application”, ...)
 */
public function myAction(Request $request, Application $application)
{
    $user = $application->getUser() !?? $this->getUser();

   // ... do something with user, without worrying about it being null.
}


> Is there a 3rd or 4th use-case you have that are unlike the first two?
>
>
I will let you know when I think of them. I totally understand how much
easier it is for others to conceptualize with good examples. I want to be
concise and relevant at the same time, and that’s actually pretty
difficult. :-)


> -Mike
>
>
>
> --
"Do not go gentle into that good night. Rage, rage against the dying of the
light." — Dylan Thomas

---

## #107688 — Ken Stanley — 2019-10-25T02:36:43+00:00

URL: https://externals.io/message/107661#107688

This got rejected for being too large???



> Now we’re talking. :-)
>
> This example is better indeed.
> > […]
>
> Sure, but that limits you to use cases on the same object. With !?? You’d
> be free to both use the same object, OR to use a different construct based
> on a semantically related (but technically different) construct: $userId
> !?? $this->getuser();  — It’s an example, so don’t get too hung up on the
> color of the bike shed.
>
>
> > […]
>
> To me, and I respect if this isn’t a popular opinion, DRY applies to
> processes, logic, and constructs. Things like variables and non-logic is
> (again imo) a step too far.
>
> In other words, the repetition of a variable name in a finite scope as
> intended for this operator (ie within a line or two of each other) should
> not be an argument for being DRY.
>
> Again,
>
> if (isset($_POST[‘field’]) {
>     $this->doSomething($_POST[‘field’]);
> }
>
> Is absolutely no different than
>
> $_POST[‘field’] !?? $this->doSomething($_POST[‘field’]);
>
> And the same goes for $foo !?? $foo->getBar(); .
>
>
> > […]
>
>
> No. The aim is not to reduce variable usage. It’s to reduce boiler plate
> code for a very common, and unnecessarily verbose coding pattern. In other
> words, it’s syntactic sugar.
>
> Yes, I appreciate that “syntactic sugar” may be considered as a
> four-letter word by some, but that does not dismiss the usefulness of such
> syntax.
>
> The fact that it’s a counterpart to an existing syntax l, I believe,
> further warrants it’s inclusion into the language. Why should t we have the
> ability to do something when a value is not null? Why should we be forced
> to be verbose about it?
>
> I refuse to accept the “this can be done using if’s or &&” argument,
> simply because operators like ?? and ?: already exist.
>
>
> > […]
>
>
> This would be invalid because isset() returns Boolean. ?? deals with
> bulls, and naturally !?? deals with non-nulls. You’re thinking ?: which
> deals with truthy/falsey values. That may be a separate (future) RFC. ;-)
>
>
> > […]
>
>
> Well thank you for the latitude. As much as I’d like to have written a
> perfect informal proposal, I’m not that lucky. :-)
>
> As far as flow control, let’s make no mistake, ??, ?:, and the idea of !??
> are all succinct forms of flow control. To pretend otherwise is a bit
> naive. Their entire existence is purely syntactic sugar so we do not have
> keep writing the same boiler plate over and over.
>
> The goal here is to merely introduce a natural progression of ?? by
> offering the ability to do something when a non-null value exists. I
> understand it’s niche, but so is ?? for that matter.
>
>
>
> > […]
>
>
> You’re right. I didn’t think my counter argument all the way through in
> your given example. But, for the sake of argument, at first glance your
> syntax makes zero sense because it’s (to me, a PHP and JS dev) not a common
> paradigm. At least putting a ! in front of ?? has a natural association and
> does not require any esoteric knowledge.
>
>
> > […]
>
>
>
> So far it seems like the biggest concern(s) is that we would most likely
> repeat the use of variables (nothing new), and that there are other ways to
> do the same thing (again, nothing new). And of course the most valid
> argument of all: adding more operators to the soup mix. Personally, I don’t
> see these as show stoppers, at least given that the idea is not too wild
> and out there.
>
> I am going to assume at this point I should have enough feedback to
> warrant putting together a thorough RFC. But don’t let that stop anybody
> else from chiming in. I welcome the additional feedback.
>
> Seriously, thank you all for taking the time to help me defend my thesis
> (if you will).
>
> - Ken Stanley
>
> > […]
> "Do not go gentle into that good night. Rage, rage against the dying of
> the light." — Dylan Thomas
>
-- 
"Do not go gentle into that good night. Rage, rage against the dying of the
light." — Dylan Thomas

---

Next page: https://externals.io/message/107661.md?page=2
