Newsgroups: php.internals
Path: news.php.net
Xref: news.php.net php.internals:109948
Return-Path: <rowan.collins@gmail.com>
Delivered-To: mailing list internals@lists.php.net
Received: (qmail 58015 invoked from network); 30 Apr 2020 17:08:55 -0000
Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5)
  by pb1.pair.com with SMTP; 30 Apr 2020 17:08:55 -0000
Received: from php-smtp4.php.net (localhost [127.0.0.1])
	by php-smtp4.php.net (Postfix) with ESMTP id 2DBC21804B4
	for <internals@lists.php.net>; Thu, 30 Apr 2020 08:42:37 -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.1 required=5.0 tests=BAYES_00,DKIM_SIGNED,
	DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,HTML_MESSAGE,
	RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_PASS
	autolearn=no autolearn_force=no version=3.4.2
X-Spam-ASN: AS15169 209.85.128.0/17
X-Spam-Virus: No
X-Envelope-From: <rowan.collins@gmail.com>
Received: from mail-il1-f179.google.com (mail-il1-f179.google.com [209.85.166.179])
	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
	 key-exchange ECDHE (P-256) server-signature RSA-PSS (4096 bits) server-digest SHA256)
	(No client certificate requested)
	by php-smtp4.php.net (Postfix) with ESMTPS
	for <internals@lists.php.net>; Thu, 30 Apr 2020 08:42:36 -0700 (PDT)
Received: by mail-il1-f179.google.com with SMTP id r2so1777629ilo.6
        for <internals@lists.php.net>; Thu, 30 Apr 2020 08:42:36 -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;
        bh=TCsWzdTbk6WFhQyjxcaJ50QzAv0TfmznbWOxmKv6NBg=;
        b=GoyGcmA5WgwToG2Mmc/KFLPEWWXjqgyt16hMry4pAfe+kPxGEiNnb5pabvYu4FR0zp
         Ou2qkoWMjb4p3tQBx5jWoT/W8D4J2uVwi+dBDKem32XmnrlZCHI1dNDybprh430/qLwd
         1BZPFDAm9b2gaJs4U7/7bH48jEQosf+8K4cHEazt4Yw42zdCQntZznjxUNIsFQ1J6j1/
         zT9ph/tShnLxPF6yuybWk3nbt/s5yspRzrM0iPLNj+tVAHmzUQrRQWecNOSPZ0ZtviCK
         MiEvQeFJBhzo10xmtEQc2VtTrLAw4v2HiTCd6/TUaNX/2LqIwmut5iA6uP9kYXQrjjKM
         aAmw==
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;
        bh=TCsWzdTbk6WFhQyjxcaJ50QzAv0TfmznbWOxmKv6NBg=;
        b=W3awqk8kjG+5iIqGJ3ZXgOuOQ0YYmo2n4u5XM4/6jbDJTWPjOIoNxbaZHYyIvuP4KG
         nnSby10njsaQm7Myn2/JNqxqT/TLKt8HSt2LvFmVYEV7VA0b822ufZgJSliMPmbJQlZg
         yKIgsEPoGPu/wbxybUEZEQNMgJifKC4PA9hIRswyv1n5dofq3V3tYkly+FuKnFzBkzBb
         at3f/bFGkscafbm/VR4Eg3WuWdovrwYFYRS3yNP12kLieTXDXhOvTddwz2BV5G2psLZ+
         S0vOnEAOLI+oXCrCe7v6CSi20ILGQ5bs05Pdj3zcW8wkgAmidvmNRWHhTj9SZRLkUzlm
         GRSQ==
X-Gm-Message-State: AGi0Puar58vtwrNXp+C+6yPCT0nC94mNcok6403dMYQQLEd897ImR1pE
	UYmYd8F17h5CyZ9tGdTdqfFUTPmWM6rXXG0nsoNicuVZ
X-Google-Smtp-Source: APiQypJ/aBdeU79bhds1BhqB++aZepFlLO0GV7XK7BbW0ucZ2UOQn82nzsacMGOs1UAvsRPDWSQFUKaIF5V1wYz1iTg=
X-Received: by 2002:a05:6e02:dcf:: with SMTP id l15mr2631052ilj.225.1588261352687;
 Thu, 30 Apr 2020 08:42:32 -0700 (PDT)
MIME-Version: 1.0
References: <CABAhh3GKb8+zMpZRYEMeZ2c3J=ztXbXsZmsp9oVVPdS4LN=Sdg@mail.gmail.com>
 <CAPyj-LAjmiEPVwQbMnnT1xT+xOdSbWUzExyKN4cBmicHcyBjdg@mail.gmail.com>
In-Reply-To: <CAPyj-LAjmiEPVwQbMnnT1xT+xOdSbWUzExyKN4cBmicHcyBjdg@mail.gmail.com>
Date: Thu, 30 Apr 2020 16:42:20 +0100
Message-ID: <CALKiJKopmg=Y+inBvhgf--UwJKX2fXEq0xgBZYjUPtS557wsLQ@mail.gmail.com>
To: php internals <internals@lists.php.net>
Content-Type: multipart/alternative; boundary="000000000000bcd00105a483e9cc"
Subject: Re: [PHP-DEV] [VOTE] match expression
From: rowan.collins@gmail.com (Rowan Tommins)

--000000000000bcd00105a483e9cc
Content-Type: text/plain; charset="UTF-8"

On Thu, 30 Apr 2020 at 13:18, Ilija Tovilo <tovilo.ilija@gmail.com> wrote:

> There are three potential use cases for language wide block expressions.
>
> 1. Match expressions
> 2. Arrow functions
> 3. Everything else
>
> The problem is that they all have slightly different semantics.
> [...]
>


I don't think that's actually true. If I'm understanding you right, you're
concerned about two things:

* Blocks which don't have a return value where one is expected / required.
* Blocks which do have a return value where one is not expected.

The language already has an established convention for both cases: a
function with no return statement evaluates to NULL in expression context,
and a function with a return value can be used in statement context and the
result discarded. I see no immediate reason block expressions couldn't use
the same rule.




> $y = match ($x) {
>     1 => {}, // Error, this does require a return value
> };
>


This could evaluate the block to null, and thus be equivalent to:

$y = match ($x) {
     1 => null,
};



$x = fn() => {}; // This is fine, the function returns null
> $x = fn(): ?int => {}; // Uncaught TypeError: Return value of
> {closure}() must be of the type int or null, none returned
>


I had no idea that was an error; I guess it's the counterpart to ": void" -
a style check rather than an actual return type check. But I don't see a
particular problem with a short closure giving the same error as the
equivalent named function (function foo(): ?int {}) so there doesn't seem
to be anything extra to define here.




> $x = fn() => {
>     foo();
>     bar();
>     <= baz(); // Why should we allow this? You can just use return
> };
>


Because right now, you *can't* use return; there are no block bodied short
closures. If we did allow "return" here, there's no *fundamental* reason
not to also allow it in a match expression, meaning "return this as the
value of the match expression" (we might not *want* to reuse the keyword,
but we *could*).




> // All of these are errors, return value is required
> $x = {};
> foo({});
> {} + 1;
> // etc.
>


They would be evaluated as empty statements, and "return" null:
$x = null;
foo(null);
null + 1;




> It's also highly questionable whether use case 3 is actually very
> useful at all because PHP doesn't have block scoping and all the inner
> variables will leak out into the outer scope.

[...]

> An additional complication is that blocks already exist as "statement
> list" statements
>


We could potentially solve both of these by introducing a new syntax which
made something explicitly a block expression. I'm not sure what the keyword
would be; "do" is already used, and "eval" has bad connotations, so I'll
use "block" as a straw man to demonstrate.

// block expression as RHS of assignment
$this->foo = block {
    $bar = new Bar();
    $foo = new Foo();
    $foo->bar = $bar;
    return $foo;
};
// $this->foo has been assigned, $bar and $foo are no longer in scope


// block expression as arm of match expression
$y = match ($x) {
    1 => block {
        foo();
        return bar();
    },
}
// if $x===1, foo() is executed, then $y gets the result of bar()


// block expression as result of short closure
$f = fn($x) => block { foo($x); bar($x); };
$f();


// even if the expression result isn't used, the scoping could apply
if ( foo() ) block {
    $x = 1;
};
// $x is not defined here
// note trailing semi-colon, for the same reason you need one after a
standard anonymous function definition
// the above is actually equivalent to this:
if ( foo() ) {
    block {
        $x = 1;
    };
}


I don't know if I *like* this idea, but it would be a consistent
language-wide implementation of the concept with minimal compatibility
impact.




It's not that black and white. I work in a lot of legacy projects that
> could benefit from match expressions but it's simply not realistic to
> refactor every single switch statement that contains more than a one
> liner.
>


To use Larry's codenames, would those specifically benefit from "rustmatch"
(evaluating the switch to an expression) or from "switchng" (a stricter
switch statement)? I'd be interested to see a real-life example where you'd
want both the match to evaluate to a value, and the arms to contain more
than one statement.

Regards,
-- 
Rowan Tommins
[IMSoP]

--000000000000bcd00105a483e9cc--