Perlモジュールでプライベートメソッドを作る

Perlオブジェクト指向はかなり後付けでムリヤリ感があるんだけど、privateメソッドをモジュールに作りたいなと思った場合にどうするか。というのを調べてみた。

概要

以下、ある秘密値を取得するメソッドを隠蔽したいケースを考える。実はこのメソッドは、中で単にrand(10)しているだけなのだが、何か妙な理由があって、どうしても外部から直接はアクセスできないようにしたいこととする。

例1)アンダースコアで始まる名前にする

Perlでは暗黙の了解として、あるモジュール内の関数名がアンダースコアで始まっていれば、それは「Privateメソッドだから外から使おうとするんじゃねぇ」という意思表示である。

ということで、アンダースコアで始まるサブルーチン名で作っておけばよい。

sub _get_secret {
  return int(rand(10));
}

シークレットを取得する関数だ、外から使うなよ! ということで先頭をアンダースコアにしている。

もっとも、これはそういう意味にしておこうというだけなので、実際に外から使おうとすれば普通に使える。ということで、それが気にくわない人はどうするか。

例2)無名サブルーチンのリファレンスを宣言する

もう少し厳密にPrivateメソッドを作りたい場合は、perlsubドキュメントにやり方のヒントが書いてある。モジュール内で、無名サブルーチンのリファレンスを保持するレキシカル変数を作ってやれば良い。

my $secret_method = sub {
  return int(rand(10));
};

こうすればこの変数は、モジュールの呼び出し元からは隠蔽されているため、勝手に外から使われることは無い。

サンプルソース

まずSecret.pmというモジュールがあるとする。

#!/usr/bin/perl
package Secret;
use strict;
use warnings;

sub new {
  my $pkg = shift;
  bless {
  }, $pkg;
}

my $secret_method = sub{
  return int(rand(10));
};

sub get_secret {
  my $self = shift;
  return $self->$secret_method;
}

1;

で、main.plからこんな感じで使われるわけやね。

#!/usr/bin/perl
use strict;
use warnings;
use Secret;

my $obj = new Secret();
print $obj->get_secret();

どっちを使うべきなのか

さて2つのやり方を紹介したが……現実的にはアンダースコアで始まるメソッド名を付けておけば十分である。CPANのモジュールのソースを見てみれば分かるけど、ほとんどはモジュール内でのみ使うプライベートメソッドをこのアンダースコア形式にしている。だから、わざわざトリッキーなことをする必要ない。

「だって、外から呼ばれちゃうかも……」と言う人には、「うるせぇ、知るかボケ」と返すのがPerl流なのだろう。ということで、細かいこと気にしなくていい。

なんか実用性皆無な記事だけど、おわり。