2016-11-25 7 views
5

Sub::Quoteによって生成されたコードのキャプチャされた変数を弱体化したいと思います。Sub :: Quoteを使用したキャプチャの弱化

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 
} 

と出力:たとえば、ここでは非引用された代替です

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; 
} 

と出力:

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

そして、ここでは私のサブ::引用試みです

foo 
foo 

明らかに、キャプチャされた$yは弱くはありません。キャプチャされた変数を弱めるために生成されたコードを変更する方法はありますか?

ドキュメントは疎であり、Sub::Quoteの実装は複雑です。私はこれが現在のコードでは不可能だと確信していますが、私は間違っていることが示されたいと思います。

+0

実際に何かを弱めるのか?それがうまくいけば、$ yを弱めた直後に '$ y'が' undef'になると思ったでしょう。 – melpomene

+0

@melpomene、私はそれが何であるかわからないが、CVへの2番目の参照がある(Devel :: Peekの 'Dump'を使って見られるように)。 ///それは、 '$ y = undef; 'はOPが期待するように実際にサブを解放しないということです。デモに影響を与えずに 'weaken'への呼び出しを取り除くことができました。 – ikegami

+0

@ikegami 2番目の参照はoptree自体にあると思います。サブはクロージャではないので、おそらくコンパイル時に作成され、永遠に残っています。 – melpomene

答えて

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

が略

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

と同じである(それはよりないが、これらのビットはこの質問とは無関係です)。ご覧のように、サブ[1]への新しい強力な参照が作成されます。使用して

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

これを達成することができる:

回避策として

、あなたは間接の層を追加することができ

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

$yがあれば問題はないだろうSub :: Quoteによって作成されたものは$yのエイリアスでした。これは、Data :: Aliasまたは5.22で導入された実験的な機能を使用して実現できます。

これは、以下のものを使用して証明することができる。

{ 
    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 }); 

あなたはエイリアシングの使用を原因となるオプションを追加することについて、モジュールのメンテナに話すことができました。


  1. あなたは(強いまたは弱い)参照のコピーを作成すると、それは強い参照です。
+0

私の答えを更新しました。 – ikegami

関連する問題