Perlのレキシカルサブルーチンとperlcritic ― 2022年12月21日 02時48分
この記事はPerl Advent Calendar 2022の21日目の分です。
Perlでは、関数内で定義した関数も外部から見えてしまいます。
use feature 'say';
sub foo {
sub bar {
say 'bar';
}
bar();
}
# foo関数の外でもbar関数を呼び出せる。
bar();
特定のスコープでのみ参照できる関数を定義したいときは、関数定義をsub
ではなくmy sub
(またはstate sub
)から始めます。この機能はレキシカルサブルーチン(lexical subroutines)と呼ばれます。
use feature 'say';
sub foo {
my sub bar {
say 'bar';
}
bar();
}
# 未定義の関数呼び出しによる例外が発生する。
bar();
ちょっとした処理をまとめるのに便利なレキシカルサブルーチンですが、perlcritic
との組み合わせに難がありました。レキシカルサブルーチンを使ったコードをperlcritic
にかけると、Subroutines::ProhibitNestedSubs
ポリシーとSubroutines::ProhibitBuiltinHomonyms
ポリシーのエラーが出てしまうのです。(perlcritic
はPerl向けのリンターです。詳しくは「perlcriticとのつきあい方 - 私が歌川です」などを参照してください。)
Subroutines::ProhibitNestedSubs
ポリシーは関数の入れ子を禁止します。入れ子の内側の関数が意図せず外部に公開されるのを避けるためのものなので、もともと外部に公開されないレキシカルサブルーチンに対しては禁止する意味がありません。
Subroutines::ProhibitBuiltinHomonyms
ポリシーは組み込み関数と同名の関数を禁止します。perlcritic
の内部で使われるで使われるPPI
モジュールの不具合により、レキシカルサブルーチンの名前は常にsub
であるとみなされていました。
これらの問題を解決するため、昨年perlcritic
とPPI
に以下のプルリクエストを提出しました。
- Allow lexical subroutines to be inside subroutines by nanto · Pull Request #971 · Perl-Critic/Perl-Critic
- Stop improper violation for lexical subroutines in Subroutines::ProhibitBuiltinHomonyms by nanto · Pull Request #973 · Perl-Critic/Perl-Critic
- Return correct name for lexical subroutines by nanto · Pull Request #261 · Perl-Critic/PPI
この年末までにこれらの変更がすべて取り込まれたので、perlcritic
(とPPI
)のバージョンを最新にすれば、心置きなくレキシカルサブルーチンを使えます。
最近のコメント