Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:129583 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by lists.php.net (Postfix) with ESMTPS id 183C81A00BC for ; Wed, 10 Dec 2025 16:23:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1765383825; bh=w78NbjzZQYpY2n/Xj5NMGm50owp2KPl9iiGx7qQQq7s=; h=Date:From:To:Cc:Subject:In-Reply-To:References:From; b=OVz63apSokDy7jtUZPKTnrlbyhdx0U1yzAvjz0hR05oVuucUINZgruefcHCvCn/fW ul8ayAABy5IIK9PujYVplk+0KTWle8qvY9lSX4oCjfVDbPaeSzZoJ3+1cI2MkiUNeb h/8tt5T7qWS2mGqvcO4IoIJ2fdLKPXmGJgZygqSzZJjkPnTzc1lN5ZjB6pyaXEO72r Z4uGHEedr7G6umoZznqfgLS6dm2eqrRCvWYHxVlnE5ytPKBeg6068KZoxsSknJv5lS 7PzIikGj96mNiRs6qHIVy7VIBFDnVrnrtQqj4LWUs0QY7U3VVkAaBViBHlPnOGUxJR fzrjI/txQ4y6Q== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 483DA180034 for ; Wed, 10 Dec 2025 16:23:44 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=0.6 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,SPF_HELO_NONE, SPF_PASS autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: No X-Envelope-From: Received: from chrono.xqk7.com (chrono.xqk7.com [176.9.45.72]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Wed, 10 Dec 2025 16:23:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bastelstu.be; s=mail20171119; t=1765383816; bh=b+tBeoeq6L7tzTfvtvSrkH5VEkheHMNgYlYSHglXbwU=; h=MIME-Version:Date:From:To:Cc:Subject:In-Reply-To:References: Message-ID:Content-Type:from:to:cc:subject:message-id; b=knE1xoiyW8bSfCQi3X6/wYSmkSW1JV8xjbN5W1a3pYZM/UpOom6j7qgfJgK05EBlc HyaexDAgumn8dwq6bBgY51oqhatas519c11s6+1y9wc9isVvwXqv32DncWuTxgURih 01PugED+hTRvkJ0Zl2BDhWwGttbcFo0BM1It6oBwGzsfR4zp39k8tt0TBacdZe16Mu nqNtBHOM8ihn5/syU1b/G0PA7xY2b0dd+geC/P2qE+ZJLv9VzJiu9h3g4WglZx69q9 lecqlDDwljLXEi+cuubBq2g2wgM9oX9TO3UgJXPVZAZFQgBLZs2hDxZIep5rYb7y0f BS7/vsrqWjTcg== Precedence: list list-help: list-unsubscribe: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 Date: Wed, 10 Dec 2025 17:23:36 +0100 To: "Rowan Tommins [IMSoP]" Cc: internals@lists.php.net Subject: Re: [PHP-DEV] [RFC][Discussion] use construct (Block Scoping) In-Reply-To: <7c623161-cde3-4fc0-944c-ddfc2785c845@rwec.co.uk> References: <1F3473C7-5D83-48D3-964E-A63D6F44D21E@rwec.co.uk> <4998b4c6-0474-4f0c-b63a-9909b8acfa96@bastelstu.be> <018421f64342a0d960589b4c8eea5cc5@bastelstu.be> <84b9dc16-3eb3-4283-b015-3af29fc0e55d@rwec.co.uk> <590fa655-d170-43f2-984c-d0a5ff6c30e4@bastelstu.be> <7c623161-cde3-4fc0-944c-ddfc2785c845@rwec.co.uk> Message-ID: Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit From: tim@bastelstu.be (=?UTF-8?Q?Tim_D=C3=BCsterhus?=) Hi Am 2025-11-29 20:12, schrieb Rowan Tommins [IMSoP]: > I think the reason comparing to other languages is so important relates > to what Steve Klabnik calls "the Language Strangeness Budget": > https://steveklabnik.com/writing/the-language-strangeness-budget/ > > Anything that is going to surprise users coming from other languages > carries a cost which we need to justify. Generally, that means either > a) the expected way wouldn't work in PHP for some reason; or b) we > think we can do better by learning from the problems of other > languages. > > In basically every language derived from ALGOL and not from Pascal, > variable declarations take the form of a statement inside a block, so > doing something different definitely costs us some Strangeness Budget. I generally agree that it is important to not needlessly invent new stuff folks need to learn and I'm trying hard in the design of my RFCs and the discussion of other RFCs to figure out how to simplify things or make them compose better. Syntax that is unfamiliar to users coming from other languages is bad, but that shouldn't come at the expense of users that are already familiar with PHP or the internal consistency of PHP. I'd also argue that the proposed `let()` block syntax is intuitive to understand when seeing it when familiar with block scoping, so it has only a small impact on the strangeness cost. FWIW: The proposed `let()` block is not too dissimilar from the `let = in ` syntax available in ML-style languages such as OCaml or Haskell and also Nix. > You've tried to make the case that PHP has unique challenges with > variable declarations, but I'm not convinced. > > In particular, I don't think this statement is accurate: > >> Other languages with block scoping, particularly statically typed >> languages, avoid this ambiguity by requiring all variables to be >> explicitly declared > > […] > > Every such language has to answer the same question: does "my_var" at > line B refer to the block-scoped variable declared below it at line C? That sentence you quoted was specifically in the context of the initial paragraph of that section, contrasting PHP - where block scoping is expected to be used comparatively sparingly - against languages where variable declarations are a more “bread and butter” part of the development process, because formally / explicitly declaring variables is a necessity for one reason or another. > The only way to *avoid* the ambiguity is to forbid all statements > between the start of the scope and a declaration - that is, raise an > error even if line B doesn't reference "my_var". Notably, if you keep > the ALGOL-style declarations, you can start with this rule, and then > relax it later, as happened with C99. > > So if it's not because we can't implement ALGOL-style declarations, is > there something we think we can do better than them? I feel that the C99 requirements and syntax would still have more ambiguity compared to the proposed `let()` syntax in cases like this: { let $foo = bar($baz); // What is $baz referring to? Particularly if it is a by-reference out parameter. let $baz = 1; } because there is a much less direct / less rigid relationship between the individual `let` statements, leaving room for interpretation of “what is considered a statement”. As an example, is a goto jump label a statement? { let $foo = 1; label: let $bar = $foo++; goto label; } Forcing all the declarations into a single statement would resolve that ambiguity, but I feel like that those restriction would feel arbitrary and have a strangeness cost without any of associated benefits that the `let()` block has. > As far as I can see, any proposed statement of the form "let($foo) { > ... }" is directly equivalent to ALGOL-style "{ let $foo; ... }" Yes, that is my understanding. > The unique innovation appears to be when using it with a single > statement rather than a block, such as in this example from the RFC: > > let ($user = $repository->find(1)) if ($user !== null) { ... } > > With ALGOL-style declarations, that requires an extra pair of braces: > > { let $user = $repository->find(1); if ($user !== null) { ... } } > > […] > > It's an interesting feature, but whether it's worth the cost in > "strangeness", I'm not sure. Being able to declare variables with “if” lifetime that I can also check is a big part of the benefits of the proposed syntax and something I'm missing in other languages. C++ as a language in the “PHP syntax family” added it in C++17 with the following syntax (taken from https://en.cppreference.com/w/cpp/language/if.html): if (char buf[10]; std::fgets(buf, 10, stdin)) if (std::lock_guard lock(mx); shared_flag) Translated to PHP this would be: if (let $user = $repository->find(1); $user !== null) { } which would somewhat match the syntax of a `for()` loop with the semicolon. But then the more composable let ($user = $repository->find(1)) if ($user !== null) { } would not be so different syntax-wise and would not require adding the grammar to each and every control structure. > On the other hand, I note that the "process_file" example in the RFC > can't make use of the single-statement form: "let ( $lock = > $file->lock(LockType::Shared) ) try { ... }" would be legal, but > wouldn't release the lock until after the catch block. As discussed in the sibling thread, allowing a single statement on `try` should be possible (if necessary with a special case for `let`): https://news-web.php.net/php.internals/129582 Best regards Tim Düsterhus