Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:107673 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 7336 invoked from network); 25 Oct 2019 00:02:38 -0000 Received: from unknown (HELO php-smtp3.php.net) (208.43.231.12) by pb1.pair.com with SMTP; 25 Oct 2019 00:02:38 -0000 Received: from php-smtp3.php.net (localhost [127.0.0.1]) by php-smtp3.php.net (Postfix) with ESMTP id 4EF6E2C0530 for ; Thu, 24 Oct 2019 14:49:07 -0700 (PDT) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp3.php.net X-Spam-Level: X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,HTML_MESSAGE,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS3215 2.6.0.0/16 X-Spam-Virus: No Received: from mail-vs1-xe2e.google.com (mail-vs1-xe2e.google.com [IPv6:2607:f8b0:4864:20::e2e]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by php-smtp3.php.net (Postfix) with ESMTPS for ; Thu, 24 Oct 2019 14:49:06 -0700 (PDT) Received: by mail-vs1-xe2e.google.com with SMTP id v10so80986vsc.7 for ; Thu, 24 Oct 2019 14:49:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=Wc9MdqL+RBTdN0z0nusLBB4Vt/wDTwvtCvbPxqz3OHg=; b=P36wSFvG161wTG1/n2Q6I/8rs/hVTCsYCVwRTsYsOVhhjBABCvUZdsbjA+z92mQg8s 4KG6Sje1DjCSOvNBlR75rmZ0y9H2GNlBac2YQG6GNoMrPq7r+l6dng6yCgrMZAWjBDzD IdJ4vgEPRENRwbJOv1nyIjAPSqltKtde5eEVATRjMmaX8g8a9QENiqEVLVoDEOvwWBJG 95XmuU+/PoVRf+GFz9hXw0Iw4Sv4ap1DAB3Lil09MQmGxofyPv0WHrB694Kr2bJdNiVp E01ieg3a8gh5RSNF7AiyYejjae7Axc/p1Cwu5CpIMJVPDp6UCOpWtskqCPN4U4RRN4If EtSw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=Wc9MdqL+RBTdN0z0nusLBB4Vt/wDTwvtCvbPxqz3OHg=; b=AVsrE7RDBItliVbd0UN4ahf3g/vJFOVzS4ZF7FtrcL9Y4SEIK7HurXeMUrIeLz2iN3 ZIhh/DNxyrK2GMViaW9A8x8o4R1l0CRPkjG+0MDnyj/Z5c0LdtZIPxDxrOR/NM6JzG8S I3OETNvQVadg5+ufU3tX+tctz4icOXYGHqRIt6SJAZcbXngsb9p+tbqSpPvf7dLCUjFQ qalHvhBfUWYJGyKY4GqFQl1f2o5HCSNy2lLp+MvRxKjqiGeT+dB7FCVoAKTwOgL5iUWH zKIvlm0DdjMXH4PCGQmbt3eSSjc4MNFqxu4X8hbu/4NnlGOmPGSJOMPbHppKd866nowu j6Iw== X-Gm-Message-State: APjAAAWwEV1K7Vk6x2lpIbOQ6PUh8aE9TqPmtaLuldsVcIyZZzrr0JYY VdeHuPMbjdEhiR/hxRb0rUfBtVpoiYiNdRIghM8= X-Google-Smtp-Source: APXvYqyJI+qkvgXnS46+JUVYU/wm6ydST9jI04hma3QkiUlHtGPWNoONnkJSHt0UJkYItosxAHivfKrzQ9yDrPfP8K0= X-Received: by 2002:a05:6102:36a:: with SMTP id f10mr247728vsa.44.1571953746201; Thu, 24 Oct 2019 14:49:06 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: Date: Thu, 24 Oct 2019 17:48:53 -0400 Message-ID: To: Andreas Hennings Cc: Dan Ackroyd , PHP internals Content-Type: multipart/alternative; boundary="000000000000a54ee10595af00c8" X-Envelope-From: Subject: Re: [PHP-DEV] [RFC] anti-coalescing-operator From: dohpaz@gmail.com (Ken Stanley) --000000000000a54ee10595af00c8 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Thu, Oct 24, 2019 at 4:29 PM Andreas Hennings wrote: > On Thu, 24 Oct 2019 at 20:59, Ken Stanley wrote: > > > > On Thu, Oct 24, 2019 at 1:33 PM Dan Ackroyd > wrote: > > > > > On Thu, 24 Oct 2019 at 18:21, Ken Stanley wrote: > > > > > > > > Since PHP 7.0 brought forward the Null Coalescing Operator (??), > writing > > > > more succinct code for how to handle null values has been a blessin= g. > > > But, > > > > what about the inverse when you want to do something when a value i= s > 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 > > > > > > > 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 !??: > > > > > class ExampleController > > { > > /** > > * PATCH a User object. > > */ > > public function saveAction(int $userId) > > { > > $user =3D $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 !??: > > > > > class ExampleController > > { > > /** > > * PATCH a User object. > > */ > > public function saveAction(int $userId) > > { > > $user =3D $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. 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 =3D=3D has != =3D=3D and > has <). I=E2=80=99m curious to what you find misleading about it? Its meant to lite= rally 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: user !?? $this->user->getName(); } } compared to: user instanceof User return $this->user !=3D=3D 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 !=3D=3D $fname =3D $_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 =3D ($x ??! NULL) * ($y ??! NULL); > > or the NULL can be omitted: > > $product =3D ($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! --000000000000a54ee10595af00c8--