Re: Re: [VOTE] let construct (Block Scoping)

From: Date: Sun, 25 Jan 2026 18:40:12 +0000
Subject: Re: Re: [VOTE] let construct (Block Scoping)
References: 1 2 3 4  Groups: php.internals 
Request: Send a blank email to internals+get-129919@lists.php.net to get a copy of this message
On Sat, Jan 24, 2026, at 12:16 PM, Tim Düsterhus wrote: > My understanding the initial paragraph of your email is that the entire > functionality of the block scoping RFC could be included in the Context > Manager RFC. The Context Manager RFC uses the same "high-level" syntax > of having a dedicated block for declarations - just using using > > instead of let as the keyword and using > => instead of = for an > assignment (the latter of which was considered confusing in the > discussion). I'm sure I must be misunderstanding, because I don't follow > how the syntax of this RFC is "non-standard and clumsy" without this > equally applying to the context manager RFC. Can you rephrase? Block scoping and CMs are related and overlap, but are different things. let, in every language I am aware of that uses it, is an inline part of the variable declaration, and then they do something to resolve the "dead zone" question. Languages that have block scoping have had it from the beginning, so "variable dies at the next }" is built into the language semantics and development culture. Neither is true in PHP. So having a block-esque syntax for "only these special blocks and these special variables get block scoping" is something I have never seen before, and feels very clumsy. CMs are about packaging up setup/teardown logic to make them reusable, and therefore more ergonomic. That setup/teardown can and often does include unsetting variables, but that's not its main purpose. It's just an implementation detail. In every language with such functionality, it is a block level construct. Block scoping as presented here is essentially a "junior, limited CM", with a future scope of adding a Disposable interface to make it a less-limited CM. I fundamentally believe that is the wrong way around, and have already discussed elsewhere (I think) why forcing the context manager (packaged logic) and context variable (the variable(s) that will need cleanup) to be the same value is fundamentally limiting and flawed. I proposed allowing the using syntax to handle non-CM objects specifically to incorporate the "degenerate case" where unsetting is the only meaningful teardown, and thereby avoid the need for a boilerplate new JustUnsetTheThing($thing) for the degenerate cases. CMs can also return $this from enterContext() if appropriate, which would then have the same effect as the Disposable interface. So no matter how you slice it, having a separate CM from context variable provides more flexibility than the proposed let syntax, in a consistent and unified fashion. By tweaking CMs, we can allow it to also cover the simple, degenerate cases that block scoping handles in addition to the more robust options it naturally supports. > I'd also like to note that it was an explicit design goal of the block > scoping RFC to compose nicely with existing control structures to be > generically applicable. This enables several of the example use cases > listed in the RFC. The context manager RFC requires braces and a > proposed special case for try instead of just accepting any > statement > like block scoping does. Due to its composibility, the block scoping RFC > is even compatible with future additions to the language (provided the > future additions follow the established syntax). As an example, pattern > matching comes to mind as another way of "writing into variables". Block > scoping will just work with match: > > let ($x, $y) $result = match ($p) is { > Point(:$z, :$x, y: 4) => "x is $x, y is 4, z is $z", > }; > > to prevent $x and $y from leaking out of the match(). And > similarly to > the foreach() future scope, we could allow > match ($p) let is to > automatically block scope all variables bound by the pattern. thinking_face.gif This is sort of what we were trying to noodle through with the questions about expression-oriented using, but it didn't stick. I would have to talk to Arnaud, but I suppose it's probably possible to allow using to work on an arbitrary construct and inherit its block. I'm quite open to discussing the feasibility of that. It's really unfortunate that both proposals were worked on separately, as I do believe there are good ideas in both. But I would much rather work from the more-flexible design and then short-cut the degenerate cases, as that gives, I believe, a better outcome in the end. --Larry Garfield

« previous php.internals (#129919) next »