Skip to content

Conversation

@leonerd
Copy link
Contributor

@leonerd leonerd commented Dec 22, 2025

The refalias feature is currently experimental due to a number of limitations of its implementation, most notably the effect it has on closures such as the one illustrated in this unit test. Any change in implementation to make this case function as intended would be a large undertaking, so instead as a path towards being able to remove the experimental status from this feature, we consider this behaviour warning instead.

The `refalias` feature is currently experimental due to a number of
limitations of its implementation, most notably the effect it has on
closures such as the one illustrated in this unit test. Any change in
implementation to make this case function as intended would be a large
undertaking, so instead as a path towards being able to remove the
experimental status from this feature, we consider this behaviour
warning instead.
@leonerd leonerd force-pushed the refalias-warn-on-desync branch from 9d6094b to 260c8d6 Compare December 22, 2025 17:49
@leonerd
Copy link
Contributor Author

leonerd commented Dec 22, 2025

I'm not hugely happy about this being a runtime warning emitted by the pp_refalias op itself. Ideally it would be nice for it to be compile-time, by ck_refalias.

Unfortunately, I sat and thought about it for a while and I couldn't think of a way to reliably detect the situation in all cases at compiletime. While in some cases it can be detected, it could be that at the time the OP_REFALIAS is being constructed, a closure has not yet been created so the variable's refcount is still one, and only gets shared by some code that is compiled later, even though at runtime it would happen in the other order and thus break.

As an example:

my sub inner;
my @x;
\@x = ["break"];
inner();

sub inner { my @y = @x; }

I think the only way to reliably detect that at compiletime would be to add a new PADNAME flag to annotate every variable that is ever the target of a refalias operation, and warn when attempting to form a closure over them. But then that would hit a lot of "safe" cases too, such as the superficially similar case below, that behaves entirely differently:

my @x;
\@x = ["not-broken"];

{
   my sub inner { my @y = @x; }
   inner();
}

I don't have any good ideas besides this currently.

@happy-barney
Copy link

please look also at test at https://github.com/Perl/perl5/pull/23873/files#diff-0a339d203b77e8f749d630a9f5b59e74a9bef94e1dc4515b7027abfe92476b77R119

refaliasing in for-over loop, unlike other kind of global variables, doesn't preserve original value before loop.
Maybe bug in loop or in refaliasing, but it is inconsistent behaviour.

@leonerd
Copy link
Contributor Author

leonerd commented Dec 22, 2025

It's unclear from that link quite what you mean, but I believe this test illustrates it?

my $var = 42;
foreach \$var ( \(1, 2, 3) ) { say "VAR is $var"; }
say "VAR finished $var";
Aliasing via reference is experimental at -e line 1.
VAR is 1
VAR is 2
VAR is 3
VAR finished 3

I believe we were expecting the final line to print 42.

If that's the case, perhaps raise this as a new issue? That should just be a small implementation detail that can be fixed with the SAVE stack.

@happy-barney
Copy link

yes, test case I linked shows exactly this issue.

@leonerd
Copy link
Contributor Author

leonerd commented Dec 22, 2025

I see now opened as #24028

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants