hogashi.*

日記から何から

Perlで戻り値として呼び出した子サブルーチンのコンテキストは親と同じ

 Perl Advent Calendar 2022 の 12日目です。
qiita.com


 こういうときのことです。

sub func2 {
  # ここのコンテキスト
}
sub func1 {
  func2;
}

 サブルーチンのコンテキストは wantarray - Perldoc Browser を使うと調べられそうです。 wantarray は、 list/scalar/void コンテキストでそれぞれ true/false/undef (値としては 1''undef ) を返します。

Returns true if the context of the currently executing subroutine or eval is looking for a list value. Returns false if the context is looking for a scalar. Returns the undefined value if the context is looking for no value (void context).

https://perldoc.perl.org/functions/wantarray

 こういう感じで、呼び出し方を変えながら wantarray を見るコードを実行すると:

use feature qw(say);

sub print_wantarray {
  my $wa_str = defined wantarray ? (wantarray ? 'true' : 'false') : 'undef';
  say "  wantarray: $wa_str\n";
}

sub func1 {
  print_wantarray;
}

say 'my $val1 = [print_wantarray];';
my $val1 = [print_wantarray];

say 'my $val2 = print_wantarray;';
my $val2 = print_wantarray;

say 'print_wantarray;';
print_wantarray;

say 'my $val3 = [func1];';
my $val3 = [func1];

say 'my $val4 = func1;';
my $val4 = func1;

say 'func1;';
func1;

 こうなります。前半は print_wantarray を直接呼んだものですが、後半の func1 を介した呼び出しでも同じコンテキストになっています。同僚と、そういえばこれどうなるんだろう、という会話になり試しましたが、子の戻り値が結局親の戻り値になるので、コンテキストが同じになるのはたしかにそういうものか、という感じで納得でした。

$ perl a.pl
my $val1 = [print_wantarray];
  wantarray: true

my $val2 = print_wantarray;
  wantarray: false

print_wantarray;
  wantarray: undef

my $val3 = [func1];
  wantarray: true

my $val4 = func1;
  wantarray: false

func1;
  wantarray: undef

 ちなみに return - Perldoc Browser を省略して書いていますが、明示的に書いても同じです。 return によってコンテキストが変わったりしないのかな、と思ったら、むしろ return がコンテキストに合わせる立場でした (コンテキストによって返す値が変わりますと書かれている)。

Evaluation of EXPR may be in list, scalar, or void context, depending on how the return value will be used, and the context may vary from one execution to the next (see wantarray).

https://perldoc.perl.org/functions/return