Hi
Am 2025-12-10 00:19, schrieb Rowan Tommins [IMSoP]:
The drawback I see is that on a longer block, you have to come up with
a name for that unused variable, and make sure you don't accidentally
unset or overwrite it.
Apparently Java's workaround for that is to allow "unnamed variables",
which have the expected lifetime, but can't be accessed:
https://openjdk.org/jeps/456
try-with-resources is given as one of the example use cases ("var"
infers the type; "_" in place of the name makes it an "unnamed
variable"):
try (var _ = ScopedContext.acquire()) {
... no use of acquired resource ...
}
Notably, this is *not* the same meaning for "_" as, say, C#, where "_ =
foo()" tells the compiler to discard the return value of foo():
https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/discards
Something that came to my mind would be that the semantics of `let()`
already allow for the following to guarantee that a value stays alive
for the entire block even if accidentally reassigned:
class Scoped {
public function __construct() { echo __METHOD__, PHP_EOL; }
public function __destruct() { echo __METHOD__, PHP_EOL; }
}
echo "Before scope", PHP_EOL;
let (
$scoped = new Scoped(),
$scoped,
) {
echo "Start of scope", PHP_EOL;
$scoped = 'something else';
echo "End of scope", PHP_EOL;
}
echo "After scope", PHP_EOL;
which outputs:
Before scope
Scoped::__construct
Start of scope
End of scope
Scoped::__destruct
After scope
It is definitely on the more obscure end, but I believe it is reasonably
easy to understand *why* it works when seeing that it does work. This
semantics of redeclaring/shadowing variables within the same (not a
nested!) scope is something that folks might also know from Rust to
ensure that a temporary input stays alive for long enough without taking
up a valuable variable name:
//
https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=e5c84849b529aab5c1a5033ddfde2870
fn get_bar() -> String {
return "bar".to_owned();
}
fn id(v: &str) -> &str {
return v;
}
fn main() {
let bar = id(get_bar().as_str());
println!("{:?}", bar);
}
This is not currently valid, as the String returned from `get_bar()` is
destroyed at the semicolon, but a reference to it is still stored in
`bar`. The following however would work:
let bar = get_bar();
let bar = id(bar.as_str());
println!("{:?}", bar);
Best regards
Tim Düsterhus