The history of wantarray()

void context + BEGIN の horror 的ななにかで指名されたので答えるよ。
疑問点をまとめると以下の二点ということでいいですか。

  • なぜ特殊コードブロックの呼び出しコンテキストは不定とされているのか
  • なぜ特殊コードブロックが実際にはスカラーコンテキストで呼ばれるのか

結論からいうと,第一の疑問の答えは,特殊コードブロックを呼び出すcall_list()内のcall_sv()においてコンテキストフラグを与えていないからです。第二の疑問の答えは,call_sv()のデフォルトコンテキストがG_SCALARだからです。

まずそもそもwantarray()の歴史を振り返ると,初期のPerlにはvoid contextは存在しなかったわけですよ。
Perl 5.003_07のperlfunc -f wantarray:

Returns TRUE if the context of the currently executing subroutine is looking for a list value. Returns FALSE if the context is looking for a scalar.

つまり,wantarray()はlist/scalarを示す真偽値を返す関数だったというわけ。
そしてそのころは,内部的に存在するフラグもG_SCALARとG_ARRAYのみだったのです。しかし,G_SCALARは一見フラグのように見えますが,その値は0なので,厳密に言うとフラグではなく単に1ビットをコンテキスト情報に割り当てていただけなのです*1。このような事情で,サブルーチンを呼び出すPerl APIであるcall_sv()のデフォルトコンテキストはG_SCALARになっています。そういうわけで,特殊ブロックの呼び出しを行うcall_list()においてcall_sv()に明示的にG_SCALARを指定していたわけではないのですが,結果的にはスカラーコンテキストで呼び出されることになっていました。

ちなみに現在,Perlの組み込み関数にはvoidコンテキストと非voidコンテキストで関数の副作用が激しく変わるような*2ものはありませんが,これはこのような背景があるためだと思います。

さて,その後Perl 5.004でvoid contextが導入されたのですが,call_sv()のデフォルトコンテキストがG_SCALARだということは変わりませんでした。そして今でも,call_list()ではサブルーチンを呼び出すときにコンテキストフラグは与えず,その結果デフォルトコンテキストであるG_SCALARになります。

以上は実装面から推測した仮説です。もしかしたら,実用面での背景もあるかもしれません。

なお,これらは「不定」とされつつも明確な実装を持ちます。したがって将来のバージョンでは「不定」でなくなる可能性は十分にあると思いますし,その暁にはvoidコンテキストになる可能性もあるでしょう。

*1:なお,5.10.0現在もG_SCALARの値は0です。

*2:たとえば,voidコンテキストでは何かを出力し,非voidコンテキストでは出力するはずだった値を返す,など。