Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:107599 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 12407 invoked from network); 20 Oct 2019 23:51:55 -0000 Received: from unknown (HELO php-smtp3.php.net) (208.43.231.12) by 76.75.200.58 with SMTP; 20 Oct 2019 23:51:55 -0000 Received: from php-smtp3.php.net (localhost [127.0.0.1]) by php-smtp3.php.net (Postfix) with ESMTP id 5D47F2C7727 for ; Sun, 20 Oct 2019 14:35:26 -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=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,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-yb1-xb43.google.com (mail-yb1-xb43.google.com [IPv6:2607:f8b0:4864:20::b43]) (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 ; Sun, 20 Oct 2019 14:35:26 -0700 (PDT) Received: by mail-yb1-xb43.google.com with SMTP id r68so3460923ybf.5 for ; Sun, 20 Oct 2019 14:35:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=newclarity-net.20150623.gappssmtp.com; s=20150623; h=from:message-id:mime-version:subject:date:in-reply-to:cc:to :references; bh=GR6FWm8j/RpyKH5/RBbiXIhr1elJOgkU+N0unKqUS+Q=; b=GHZdmfYSSHuDBwNYZYThBlQTHKFNsF6tYjuwCzDS89zPUMSDGrJZbaWfXONfXVUcLV wsGFdF3z96NCoxAydgPEHYGYCeSPNxTDj4feqTaXqPlR+Xk5v1JHCVcfTxQp6govhS9A u6W1kSoTYnUwqgt7Gyv6h5Wo0ZiUG+sv7H9761D3KICz5sMrsXTD0pCPYNVICaqSap4Z k5L1bcaXq5ox+DEVEW2v8HsHA6K7NddZ1hkn/5OCQ5/wqRI4NSVnSjlX70lG6ai1/PLb uvGcEhcactrOEkmeHQ8LxD1umPmGOhhIU1+fCZIfRRuNWCNvDPIN/wYLwzxQSxcRfCfb aWeQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:message-id:mime-version:subject:date :in-reply-to:cc:to:references; bh=GR6FWm8j/RpyKH5/RBbiXIhr1elJOgkU+N0unKqUS+Q=; b=YgSTWkd7QKCDU3LuSyi+PJNre6a3GStg4zSDAaJtOj4/XYg6Aa25eOAJeFtH/uY5pz xidhl+OQWYkEIlazzhfRZiNstqqcd9H1Poxk4i9XS4zYkLDnFnZ0Ohx+43UxIm8C1ynW xeHBPxD3nw6EZSa+ksGkPhp3rTOPD++VMDuS/Fm+dGM+w8dRLVmfbNSOMjfKAvXtSWku ky9z8m6dMrL8TgdGFk5Nhs2pfCLoRxkGNUBOu2eNJDbJqR6ISCk2sAFMssl1IZCSANJf LGXo0AyWGVAEcp6s+K1CKfPCSLWX7DSpWy5OWEvR8AISk6d2ymqw3VOQgDfpaq63Dxj7 lHeA== X-Gm-Message-State: APjAAAVEhHROVAzLMSp9Ny+GAVPbziKQPkt+C0WZgAJpwonDhAzEV6N5 Nun7iQX2000QyM7xx2T8v49LyQ== X-Google-Smtp-Source: APXvYqy0M2mvOEVK3cAyFHzrNQIik9OSIzEULVJOk2LUm6Qc0y04iBnax9OtTe6qTFqqo6+hNZ++Hw== X-Received: by 2002:a25:3b10:: with SMTP id i16mr5226176yba.188.1571607325371; Sun, 20 Oct 2019 14:35:25 -0700 (PDT) Received: from ?IPv6:2601:c0:c67f:e34e:dc33:30b5:913d:fcb2? ([2601:c0:c67f:e34e:dc33:30b5:913d:fcb2]) by smtp.gmail.com with ESMTPSA id u62sm2640416ywd.15.2019.10.20.14.35.23 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 20 Oct 2019 14:35:23 -0700 (PDT) Message-ID: <91095002-BA0D-440B-8FAB-AA003A0EDB69@newclarity.net> Content-Type: multipart/alternative; boundary="Apple-Mail=_B7C0448C-0244-48DE-9B13-2885CFD43891" Mime-Version: 1.0 (Mac OS X Mail 12.4 \(3445.104.11\)) Date: Sun, 20 Oct 2019 17:35:21 -0400 In-Reply-To: Cc: internals@lists.php.net To: Rowan Tommins References: X-Mailer: Apple Mail (2.3445.104.11) X-Envelope-From: Subject: Re: [PHP-DEV] 'switch-expression' and the 'type guard' unary operator demo From: mike@newclarity.net (Mike Schinkel) --Apple-Mail=_B7C0448C-0244-48DE-9B13-2885CFD43891 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=us-ascii > On Oct 20, 2019, at 7:59 AM, Rowan Tommins = wrote: > On 19/10/2019 17:40, Kosit Supanyo wrote: >> Like function declaration and function expression in JavaScript, if >> `switch` appears as first token at statement level it will be = recognized as >> statement but if `switch` is in expression context it will be >> switch-expression. >>=20 >> switch ($expr) { >> case $cond1 =3D> $result1, >> case $cond2 =3D> $result2, >> case $cond3 =3D> $result3, >> default =3D> $default_result, >> }; >> // Parse error: syntax error, unexpected '=3D>' (T_DOUBLE_ARROW) >>=20 >> But this is OK. >>=20 >> !switch ($expr) { >> case $cond1 =3D> $result1, >> case $cond2 =3D> $result2, >> case $cond3 =3D> $result3, >> default =3D> $default_result, >> }; // semicolon is still required because it is an expression >=20 >=20 > This feels like an odd restriction to me, and one that as far as I'm = aware PHP doesn't have anywhere else. For instance, it might be = considered bad style, but it's possible to use a ternary operator as an = abbreviated if statement: >=20 > isset($_GET['logout']) ? $session->logout() : $session->extend(); >=20 > Was this restriction added to make the implementation easier, or = because you thought it was a useful feature? What restriction are you referring to? The forced `default` or the = semi-colon being required? If `default`, I concur. > I've always felt switch(true) was rather limited in its advantage over = if-elseif. I would much prefer to use a switch for multiple, mutually exclusive = cases no matter what how complex the expression is because with a switch = the cases expressions line up vertically. With `if` and `else if` it is = harder to vertically eyeball the different mutually exclusive cases. With that, I would even argue that we deprecate `else`. Except I know = that would be a battle so I wouldn't actually suggest it. :-) > I would prefer a syntax that reduced the boilerplate for: >=20 > * Different comparisons applied to the same variable/expression, e.g. = match($user->getScore()) { case <0 =3D> foo(), case >100 =3D> bar(), = default =3D> baz() } > * Different values compared against the same expression using the same = operator, e.g. match( $exception instanceOf ) { case FooException =3D> = handleFoo(), case BarException =3D> handleBar() } However, I would very much like to see both of those options, for switch = expressions and switch statements. It is "syntax sugar," but IMO[1] programming languages evolve best when = they recognize commonly used-patterns and then apply syntax sugar to = make those patterns more obvious, less error prone and easier to reason = about. Further, your introduction of a `match` keyword here is intriguing, and = we could probably leverage it for other use cases. Maybe as an alternate = to switch statements that do not require `break`s? >> $x =3D 'd'; >> $v =3D switch ($x) { >> case 'a' =3D> 1, >> case 'b' =3D> 2, >> case 'c' =3D> return true, >> default =3D> throw new Exception("'$x' is not supported"), >> }; >=20 > The "return" case in particular seems ambiguous - if $v is visible = outside the function, will it have a value assigned to it by the = "return" branch, and if so what would that value be? It should have its prior value, since the expression did not complete. =20= Alternately we could choose to always assign it null on return or break. But how often will we have this use-case? Only for global variables, = which hopefully will eventually become extinct in userland code. > This is a very interesting feature, although I think what would be = even more useful would be syntax to check if something _can_ be cast, = i.e. the same check you have here, but as an operator evaluating to = boolean. >=20 > That way, you could write code like this: >=20 > if ( $_GET['id'] ) { > $user =3D getUser($_GET['id']): > } > else { > echo "Invalid ID provided"; > } >=20 > Which would be equivalent (given a type hint on getUser() and no = strict_types declaration) to this, but without needing to use exceptions = as flow control: >=20 > try { > getUser($_GET['id']); > } > catch ( TypeError $e ) { > echo "Invalid ID provided"; > } +1 to use for can-cast checking. In GoLang this is called a type = assertion and is thus similar: if id,ok =3D get['id'].(string); ok { $user =3D get['id'].(string); } else { echo "Invalid ID provided"; } It would be super nice for PHP to have an equivalent.=20 That said, we should almost be able to do both, and just let PHP throw = an error if there is a problem. This would be useful if you know 100% = that the code won't fail because of the code that came before it: if ( is_numeric($_GET['id'] ?? 0 ) ) { $id =3D intvar($_GET['id'] ?? 0); $user =3D getUser($id): } =20 -Mike [1] https://mikeschinkel.me/2019/in-defense-of-syntactic-sugar/ = = --Apple-Mail=_B7C0448C-0244-48DE-9B13-2885CFD43891--