出口ひとつコードのもうひとつのメリット?

いまどきのLLを使う分にはたいして意識する必要もないでしょうが、出口ひとつコードがよいと言われる理由にはもうひとつ、広い意味でのガーベジコレクションの問題もありますね。サブルーチン中でいきなりdieして怒られないのはPerlのコード(パッケージやら何やら)が暗黙のうちにBEGINやDESTROYを前後に配した出口ひとつコードになっているからであって、その仕組みがなかったり、仕掛けをしてガーベジコレクションの実行を遅らせているような環境では、どこかのブロックできちんと出口をひとつにして不要なものを消してやらないと、ゴミが残ったり、最悪帰り道がわからなくなって暴走したりする。

激しくダメな例ですが、たとえば古いCGIあたりに見つかりそうなこんなコード。

sub load_counter {
  my $lock = './lock';
  my $counter;
  unless (-d $lock) {
    mkdir $lock, 0600;
    open IN, 'counter' or die; # ここも出口
    $counter = <IN>;
    close IN;
    rmdir $lock;
  }
  return $counter;
}

こんな実装でdieしてしまうとロックディレクトリが残ってえらい目にあうわけですが、ここでdieなんぞせんで、たとえば

sub load_counter {
  my $lock = './lock';
  my $counter;
  unless (-d $lock) {
    mkdir $lock, 0600;
    if (open(IN, 'counter')) {
      $counter = <IN>;
      close IN;
    }
    rmdir $lock;
  }
  return $counter;
}

とかなっていればもう少し関数の安全性やら独立性やらが高くなる。もちろんほんとはmkdirやrmdirの返り値も見るべきだし、そもそもそんな安全でない実装するよりおとなしくflockなりなんなり使った方がいい。もっと堅牢にしたければunlessのブロックをさらにevalでくくるとかなんとかする手もあるわけですが、その辺はまあ、よしなにしてくださいませ。

いいことづくめのように見えても、たとえば関数の隠蔽が過ぎると何かあったときにデバッグユニットテストが大変だったりなんて側面もありますし、そもそもある程度高級な言語だからこそ出口ひとつなんてことができるわけで、アセンブラとか回路の一部分レベルで出口ひとつコードなんてありえんですしね。凝り固まっちゃいけませんや。