Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:109289 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 34908 invoked from network); 25 Mar 2020 13:45:40 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 25 Mar 2020 13:45:40 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 70D97180088 for ; Wed, 25 Mar 2020 05:10:18 -0700 (PDT) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-0.1 required=5.0 tests=BAYES_00,BODY_8BITS, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM, HTML_MESSAGE,MALFORMED_FREEMAIL,MIME_QP_LONG_LINE,RCVD_IN_DNSWL_LOW, SPF_HELO_NONE,SPF_PASS autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS714 17.58.32.0/20 X-Spam-Virus: No X-Envelope-From: Received: from ms11p00im-qufo17282001.me.com (ms11p00im-qufo17282001.me.com [17.58.38.57]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Wed, 25 Mar 2020 05:10:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=me.com; s=1a1hai; t=1585138214; bh=SNGMvtk/yzmMkAwfncLWF+w/C6uWbqX6GPf/fahfCMY=; h=Date:Subject:From:To:Message-ID:Content-type; b=ZJ6VC2hFNjyx1iG6z3C4UAExb+0dH/fWPAVXAuPNfPq+MXPA5rTqKmCOBZM98MazO AnFO5L3I13Xo+1YubE+yvRW9SPz1npjWxoVmQm1KOfviFvGZxeGRo73VRdFj/XXpmL Ume5+m9tgDkj2RUS2IqjW2v9ddJtza9szu2PxzSYe3FeOXgk4crmRaU0H+d5mNzxlh ENoC4KnbZ3ok30ebdqqRyYpX4chGpvAFGs8a6w1Pljo+2SK8tOQEzfuC6FlPbq69j9 M3IeOchS+c4jpjdqYT7EsKyb+Oye6TqXU4w2hl+kahPZvNkWBAfIcB/BOn1IavipqK ff9QWzJGLYgaA== Received: from [192.168.1.106] (9.66.194.178.dynamic.wline.res.cust.swisscom.ch [178.194.66.9]) by ms11p00im-qufo17282001.me.com (Postfix) with ESMTPSA id D1ACBA0057E for ; Wed, 25 Mar 2020 12:10:12 +0000 (UTC) User-Agent: Microsoft-MacOutlook/16.35.20030802 Date: Wed, 25 Mar 2020 13:10:05 +0100 To: Message-ID: <047092C7-84FB-42AB-8084-7B83F76F55C1@me.com> Thread-Topic: [RFC] switch expression Mime-version: 1.0 Content-type: multipart/alternative; boundary="B_3667986613_563315031" X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:,, definitions=2020-03-25_05:,, signatures=0 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 suspectscore=0 malwarescore=0 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 mlxscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1908290000 definitions=main-2003250104 Subject: [RFC] switch expression From: ilija.tovilo@me.com (Ilija Tovilo) --B_3667986613_563315031 Content-type: text/plain; charset="UTF-8" Content-transfer-encoding: quoted-printable Hi everybody! =20 A few years ago I suggested adding a new `match` expression to the PHP lang= uage: https://externals.io/message/100487 =20 I arrogantly assumed someone will implement it for me which of course didn'= t happen. I'd finally like to get my own hands dirty. I have a very rough, i= ncomplete prototype but I'd like to get your feedback before I continue work= ing on the details. =20 # Introduction =20 This is what it looks like: =20 ```php echo $i switch { =C2=A0=C2=A0=C2=A0 0 =3D> "i equals 0", =C2=A0=C2=A0=C2=A0 1 =3D> "i equals 1", =C2=A0=C2=A0=C2=A0 2 =3D> "i equals 2", =C2=A0=C2=A0=C2=A0 3, 4 =3D> "i equals 3 or 4", }; =20 // is roughly equivalent to =20 switch ($i) { =C2=A0=C2=A0=C2=A0 case 0: =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 $tmp =3D "i equals 0"; =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0break; =C2=A0=C2=A0=C2=A0 case 1: =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 $tmp =3D "i equals 1"; =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 break; =C2=A0=C2=A0=C2=A0 case 2: =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 $tmp =3D "i equals 2"; =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 break; =C2=A0=C2=A0=C2=A0 case 3: =C2=A0=C2=A0=C2=A0 case 4: =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 $tmp =3D "i equals 3 or 4"; =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 break; =C2=A0=C2=A0=C2=A0 default: =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 throw new InvalidArgumentException('Unhandled switch case'); } =20 echo $tmp; ``` =20 Some things to note: =20 * Each case only accepts a single expression * The entire switch expression evaluates to the result of the executed case * There is no fallthrough, an implicit break is added after every case * Multiple case conditions are possible with comma separation * The default case throws a InvalidArgumentException by default * The switch keyword is used as an infix operator =20 # Syntax =20 Originally, I expected to reuse the current syntax and transform it into an= expression. =20 ```php $x =3D switch ($y) { ... }; ``` =20 Turns out this is ambiguous. =20 ```php switch ($y) { ... } [$a] =3D ...; =20 // Could also be interpreted as switch ($y) { ... }[$a] =3D ...; ``` =20 I stole the new syntax from C# 8.0 which means at least some people will al= ready be familiar with it: https://docs.microsoft.com/en-us/archive/msdn-magazine/2019/may/csharp-8-0-= pattern-matching-in-csharp-8-0#the-evolution-of-pattern-matching-in-c-80 =20 # Type coercion =20 One of the bigger weak points of the `switch` statement is the fact that it= performs implicit type coercion. =20 ```php switch ('foo') { =C2=A0=C2=A0=C2=A0 case 0: =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 echo "Oh no!\n"; } ``` =20 While it's very tempting to fix this in the new `switch` expression it adds= a confusing discrepancy between the `switch` statement and expression. I th= ink it would be preferrable to keep the two the same and change the behavior= of both in a new PHP edition (https://github.com/php/php-rfcs/pull/2). =20 # Pattern matching =20 I decided against pattern matching because PHP doesn't have algebraic data = types and classes rarely have public properties. In my opinion the limited u= se cases don't justify the significant complexity added to the language. It = would also, once again, add an unjustified discrepancy between the `switch` = statement and expression. If at some point we do want to introduce pattern m= atching it might be better to introduce a different keyword (e.g. `match`) a= nd make it work for both the statement and expression. In case you need to m= atch a more complex expression the following still works fine: =20 ```php echo true switch { =C2=A0=C2=A0=C2=A0 is_int($x) =3D> 'int', =C2=A0=C2=A0=C2=A0 is_float($x) =3D> 'float', =C2=A0=C2=A0=C2=A0 is_string($x) =3D> 'string', =C2=A0=C2=A0=C2=A0 ... }; ``` =20 # Blocks =20 Sometimes it would be useful to split the expression into multiple statemen= ts to make it more readable. Unfortunately, in PHP there are no block expres= sions. Rust allows returning the last value by omitting the semicolon: =20 ```php echo $x switch { =C2=A0=C2=A0=C2=A0 1 =3D> { =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 foo(); =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 bar(); =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 baz() =C2=A0=C2=A0=C2=A0 }, }; ``` =20 This is indeed possible in PHP and could be implemented as part of the `swi= tch` expression or as a general language feature. A nice side effect is that= this could also be used in arrow functions: =20 ```php $x =3D fn() =3D> { =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 foo(); =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 bar(); =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 baz() }; ``` =20 This would, however, make it inconsistent with closures as they use the ret= urn keyword. Thus we would probably have to make sure arrow functions still = work with return statement which would decrease the need for such a language= construct. It is also very unlike anything else in PHP. =20 # Poll =20 This is a short overview of what I'll be working on in the coming weeks. I = created a short poll for you guys to let me know if this idea is worth pursu= ing: https://forms.gle/stXMv72CAaDDxfwf8 =20 Stay safe! =20 --B_3667986613_563315031--