Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:109470 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 45145 invoked from network); 30 Mar 2020 19:45:02 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 30 Mar 2020 19:45:02 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id EEE1418050B for ; Mon, 30 Mar 2020 11:11:00 -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=-2.6 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_LOW,SPF_HELO_PASS,SPF_NONE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS11403 64.147.123.0/24 X-Spam-Virus: No X-Envelope-From: Received: from wout1-smtp.messagingengine.com (wout1-smtp.messagingengine.com [64.147.123.24]) (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 ; Mon, 30 Mar 2020 11:11:00 -0700 (PDT) Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailout.west.internal (Postfix) with ESMTP id 11B26609 for ; Mon, 30 Mar 2020 14:10:59 -0400 (EDT) Received: from imap26 ([10.202.2.76]) by compute7.internal (MEProxy); Mon, 30 Mar 2020 14:10:59 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm2; bh=MGt4Tp sdKtUHCO3WkufxsQPgBX61l+m2+HWkc7MsaTk=; b=2bgMlWmuj8TdMiCp1rx0Pe w+aY39sWJLwEXLfCaovyl/uRMyKvUR+b6ExGm+K/IhoNHYKAm1kHJgvFaR6f76CW 7sShH2xMwL/Y6JYaaxQfchPZ2KrqQmbmd5xvwV/2pnccz1wJqOzQM29TUi2ovDvH R/a6k1nn4r/+BCaqeINtArZLXGLVJ+MFk8m5a2gzWtbRPmQviN5Q6Gd2uqfc505e osKxRoiMLtS19hi2sXRv9kHd81z8yqFPg5m6HUTpFgN42lUeRe8QhHWc7ZtvbTcI 6T8U1D20OtewMSyggGeurIZ+O4gzzTgPqs8SQ0trosNCGLz27vMQ8vHVqpEX+nsQ == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedugedrudeihedguddvvdcutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfgh necuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd enucfjughrpefofgggkfgjfhffhffvufgtsehttdertderredtnecuhfhrohhmpedfnfgr rhhrhicuifgrrhhfihgvlhgufdcuoehlrghrrhihsehgrghrfhhivghlughtvggthhdrtg homheqnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhep lhgrrhhrhiesghgrrhhfihgvlhguthgvtghhrdgtohhm X-ME-Proxy: Received: by mailuser.nyi.internal (Postfix, from userid 501) id 545D714200A2; Mon, 30 Mar 2020 14:10:58 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface User-Agent: Cyrus-JMAP/3.1.7-1021-g152deaf-fmstable-20200319v1 Mime-Version: 1.0 Message-ID: <5ddebafa-1f29-4393-8b66-88026031a8a3@www.fastmail.com> In-Reply-To: References: <047092C7-84FB-42AB-8084-7B83F76F55C1@me.com> <026AF97E-ED0C-411C-8942-7DA7CC9705DB@me.com> <34ce624e-7d00-4f63-2c4f-da125deb65b8@gmail.com> Date: Mon, 30 Mar 2020 13:10:36 -0500 To: "php internals" Content-Type: text/plain Subject: Re: [PHP-DEV] [RFC] switch expression From: larry@garfieldtech.com ("Larry Garfield") On Sun, Mar 29, 2020, at 5:07 PM, Ilija Tovilo wrote: > Hi Larry > > Thanks for your suggestion. > > I chose to use switch instead of match for a couple of reasons: > > 1. It uses the same AST, code generation and opcodes as the switch, I > don't agree that it is significantly different than the switch that we > already have. > 2. Adding the `match` keyword is a breaking change, not an insignificant one. > 3. If we can fix the switch statement semantics in the future the two > will only differ in that one returns a value and the other one > doesn't. This is a much smaller distinction than functions/closure. > 4. If we'd every want to add pattern matching, we'd still have a > keyword available to us. > > > I don't believe that's the case here, however. `switch` is a language construct for a *statement*, which branches the flow of control of the program. > > > > What you're proposing is a language construct for an *expression*, which evaluates depending on internal logic to a different value. > > Well, I encourage you to look at the implementation. You'll see that > the two are in fact very similar. > > I'm not averse to using the match keyword if people are ok with the BC > change. If we do though we definitely should make it work as a > statement, allow blocks in addition to single expression and also fix > type coercion. This would make it a replacement of the switch > statement instead of an addition. > > Ilija Stas already replied and I agree with his statements, so I won't repeat them. I will, however, add a bit more: As Stas said, that the internal implementation is nearly the same is irrelevant from a language design perspective; the behavior of the syntax for the user is what matters. Essentially, its "user interface". That should be the driving factor. Introducing a new keyword in a major release seems entirely within scope. We've added keywords in minors before, too, so I'm not too worried. As to your other points: * Being strictly typed rather than coercively typed: I'd be fine with this, frankly. There may be an argument to be made that it should respect the declare statement, or something else, but making it a new construct puts using === on the table, and I'd be fine with it. * Work as a statement; allow blocks. I disagree with these strongly, for very closely related reasons. 1) match/select/whatever it's called is not a statement. It is an expression. It evaluates to something. That's its value. if you just want something that's a control statement, we already have switch. That's it's value. Not everything has to be a statement. In fact, I've seen arguments before that statements in general are a bad idea and everything should be an expression. There's a reasonably good language design argument to be made there, but at the very least we shouldn't be pretending that statements are intrinsically superior. They're very much not. The point of statements is to make some change to the state of the system. The point of an expression is to be evaluated into another, simpler value. match() is, specifically, an expression that evaluates to a value. sticking statements inside an expression is just kinda weird, and opens up the door to all kinds of side effect behavior. If you want side effects... you already have switch. 2) The use of a single-expression is, I would argue, a feature, not a defect. As above, expressions evaluate and you usually do not want them to have side effects. Allowing a block on the right side means: * It encourages side effect code. * It makes the construct visually larger, not smaller. That makes it harder to read and understand. * It discourages refactoring of multiple operations into a single operation, viz, a function call. * You have to have either have a return statement or a magic Rust/Ruby-like "last evaluation gets returned" behavior, which is unprecedented in PHP. I would argue that in the match() use cases, any time you may be tempted to use a multi-line expression what you really want is a stand-alone function. It creates a cleaner visual in place, plus encourages breaking up code into smaller, named, self-documenting bits. Those could be named functions, anon functions, method calls, etc. If you have a block of code that ends in a return... it's a function. We have ample ways to define functions already; there's no need to add another one-off way. Viz, if I see this: match($foo) { 5 => { $thing = getThing($foo); $b = $thing->extract($bar); return $b * 4; }; 6 => 'blah'; } Then I would argue this is superior in every situation: match($foo) { 5 => mapFoo($foo); 6 => 'blah'; } function mapFoo($foo, $bar) { $thing = getThing($foo); $b = $thing->extract($bar); return $b * 4; } As for pattern matching, if it supports an arbitrary left-side expression (or list of expressions) then I'm not clear what else is needed. Isn't this "close enough" to pattern matching that it coves all reasonable use cases: match(true) { $foo < 5 => $someVal; $foo < 10 => $otherVal; $foo <= 100=> $somethingElse; default => $whatever. } Switching on a type would be a bit more verbose as you'd need to repeat instanceof in each match expression, but I think I'm willing to accept that. Now, if we had proper enumerations and the ability to enforce that you exhausted the possible values (a la Rust), then I'd be on board with internalizing the type match. Sadly, I don't see that happening in the near future, much as I would support it. --Larry Garfield