Capture mitigation using Sub :: Quote

I would like to loosen the captured variables in the code generated by Sub :: Quote . For example, there is no quoted alternative:

use 5.10.0; use Scalar::Util qw[ weaken ]; { my $s = 'foo'; my $x = sub { say $s }; weaken( my $y = $x ); my $bar = sub { &$y }; &$bar; $x = undef; &$bar } 

and conclusion:

 foo Can't use an undefined value as a subroutine reference [...] 

And here is my attempt at Sub :: Quote:

 use 5.10.0; use Sub::Quote; use Scalar::Util qw[ weaken ]; { my $s = 'foo'; my $x = sub { say $s }; weaken( my $y = $x ); my $bar = quote_sub( '&$y', { '$y' => \$y } ); &$bar; $x = undef; &$bar; } 

and conclusion:

 foo foo 

Obviously, the captured $y not weakened. Is there a way to modify the generated code to weaken the captured variables?

The documentation is sparse, and the implementation of Sub::Quote is complex; I am pretty convinced that this is not possible with the current code, but I would like to be shown that it is wrong.

+5
source share
1 answer
 my $bar = quote_sub( '&$y', { '$y' => \$y } ); 

roughly coincides with

 my $bar = eval(q{ my $y = $y; sub { &$y } }); 

(He does more, but these bits are not relevant to this question). As you can see, this creates a new strong link to sub [1] .

As a workaround, you can add an indirect layer:

 my $bar = eval(q{ my $y_ref = \$y; sub { &{ $$y_ref } } }); 

This can be achieved with:

 my $bar = quote_sub( '&{$$y_ref}', { '$y_ref' => \\$y } ); 

There would be no problem if the $y created by Sub :: Quote was an alias for your $y . This can be achieved using Data :: Alias ​​or the experimental function introduced in 5.22.

This can be demonstrated using the following:

 { package Sub::Quote; my $sub = sub { my ($from, $captures, $indent) = @_; join( '', "use feature qw( refaliasing );\n", "no warnings qw( experimental::refaliasing );\n", map { /^([\@\%\$])/ or croak "capture key should start with \@, \% or \$: $_"; (' ' x $indent).qq{\\my ${_} = \\${1}{${from}->{${\quotify $_}}};\n}; } keys %$captures ) }; no warnings qw( redefine ); *capture_unroll = $sub; } my $bar = quote_sub( '&$y', { '$y' => \$y } ); 

You can talk with the module developer about adding an option that will cause the use of anti-aliasing.


  • When you create a copy of a (strong or weak) link, it is a strong link.
+3
source

Source: https://habr.com/ru/post/1260372/


All Articles