ルーチン名(関数/メソッド名)類型学入門

よいルーチン名の条件には色々あって、知りたい人はその手の本(私の手元にも4冊ある)の該当する章を読んでください――なのだが、本稿では手続き型言語におけるルーチン名の類型に焦点を当ててみたい。

比較的「マシ」だと見なされるルーチン名を観察すると、いくつかのパターンで構成されている。このパターンを踏襲することで、よいルーチン名に多少は近づくことができるのではないか、と思っている。

「動詞・(?:副詞|目的語)」型

一般的に基礎・基本とされるルーチン名の類型である。日本語に直訳すると「○○を××する」という感じだ。手続き型言語で記述されたプログラムにおいて、少なくないルーチンがこの類型に当てはまる。

sendPacket(packet);

ルーチンの強度(凝集度)が低いと「動詞・目的語 and 動詞・目的語」のような名前になってしまうことがある。「よい名前が思い浮かばなかったら、そのルーチンを疑え!」という先人の知恵には、このような背景がある。

「(?:is)?補語」型

「動詞・(?:副詞|目的語)」型と同様に、基本的なルーチン名の類型である。主に真偽値を返すルーチンにて用いられる。

if (isEmpty(ctx)) {
    throw new IllegalStateException();
}
return validMail(mail) ? mail.from : null;

特徴としては、この類型のルーチンは引数として「主語」に相当する引数をとる。つまり、このルーチンを呼び出す部分は「(?:is)?補語・主語」という記述となる。プログラマはその記述を見て「主語 is 補語」ないし「Is 主語 補語 ?」と解釈する。

「(?:on)?(?:主語)?他動詞」型

GUIなど、イベント・ドリブンなプログラムにて見られる類型である。

// Androidアプリの場合
public class MainActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        // 省略
    }

    @Override
    protected void onDestroy() {
        // 省略
    }
}

イベント・ドリブンなプログラムでは、外界からの刺激(イベント)を受けて受動的に反応する(≒何らかの処理を行う)ことになる。この時、イベントハンドラ(イベントに応じて直接呼び出されるルーチン)の名前に他動詞を用いて、日本語に意訳すると「○○された時」とでもいうべきニュアンスにすることが多い。

ここで下手に「動詞・(?:副詞|目的語)」型の命名をしてしまうと、イベントを受けて反応するルーチンではなく、能動的に何かを行うルーチンという印象を受けてしまうため、ぱっと見でイベントハンドラか否か判断できなくなる。なので避けるべきだ。

またその逆に、通常のルーチンに「(?:on)?(?:主語)?他動詞」型の命名を適用することも避けるべきだろう。

「名詞・動詞(?:副詞|目的語|補語)?」型

オブジェクト指向プログラミングに対応していない言語でオブジェクト指向プログラミング的な実装を行う場合や、言語機能としてのモジュール機構を持たない言語にてモジュールを実装する際のAPI命名において見られる類型である。

オブジェクト指向プログラミングでは、メソッド名の前にオブジェクト(インスタンス)の名前がくる。これをオブジェクト指向プログラミングに対応していない言語で真似る場合、クラス名に相当する型名を先頭に配置し、メソッド名に相当する名前を続けて書く。このようなルーチンの第一引数は、オブジェクト(インスタンス)に相当するデータ構造をとる。

/* 
 * pt1、pt2はpoint型。
 * C++なら distance = pt1.calcDistanceTo(pt2);
 */
distance = point_calcDistanceTo(&pt1, &pt2);

このケースでは、型名を除いた残りの部分は、オブジェクト指向プログラミングにみられる類型と一致する。

言語機能としてモジュール機構を持たない言語(特にC言語)にてモジュール/サブコンポーネントを実装する際は、モジュール/サブコンポーネント名前を主語とし、それ以降に「動詞・(?:副詞|目的語)」型や「(?:is)?補語」型のルーチン名を続けるような命名がされることも多い。

/* fooはモジュール名 */
extern int foo_initialize(void);
extern void foo_finalize(void);
extern int foo_startBar(void);
extern int foo_stopBar(void);

この手の工夫は、名前空間や何らかのモジュール機構(クラスも含む)を持った言語では不要だ。

その他

Unixシステムコール由来のルーチンでは「動詞」型とでもいうべき簡潔なルーチン名がよく見られる。

int fd = open(path, O_RDONLY);

同様に「名詞」型とでもいうべきルーチン名も見られる。

if (stat(path, &buf) < 0) {
    perror("stat(2)");
    exit(EXIT_FAILURE);
}

しかしどちらも、自分でルーチンを作成する際には採用するべきではない。簡潔すぎるし、既にシステムコール等で使われているので紛らわしいからだ。

例外は、「名詞」型で且つ何らかのアルゴリズムの名前である場合だ。例えばクイックソートのルーチンに「quickSort」のような名前を付けるのは問題ないだろう(クイックソートを自前で実装する必要があるか、という点は除外する)。

テキストフィルタのようなツールを実装する際には、「名詞」型の派生の「(?:do)?コマンド名」型とでもいうべきルーチン名が採用されることもある。実装するテキストフィルタのコマンド名と同名のルーチンを記述し、アプリケーション・メインエントリにて必要に応じて入力/出力ストリームを切り替えつつ当該ルーチンを呼び出す、という具合である。

/*
 * cat(1) を真似た tinycat(1) を自作しているとして……
 * 基本的なアルゴリズムは同じだが、
 * オプション指定等によって入出力ストリームを変える必要がある。
 */

/* 標準入力から読み、標準出力に書く */
tinycat(stdin, stdout);
/* ファイルから読み、標準出力に書く */
tinycat(in, stdout);
/* 標準入力から読み、ファイルに書く */
tinycat(stdin, out);
/* ファイルから読み、ファイルに書く */
tinycat(in, out);

オブジェクト指向プログラミング

オブジェクト指向プログラミングをサポートする言語においては、一般的なメソッド名として、「動詞・(?:副詞|目的語)」型に当てはまるものと、副詞/目的語のない「動詞」型の2つに分けられる。この2つを観察してみると、概ね次のような内容である。

類型 コード上の配置 意味 備考
「動詞・(?:副詞|目的語)」型 オブジェクト 動詞 (?:副詞|目的語) 主語 動詞 (?:副詞|目的語) 第1文型SVないし第3文型SVO
「動詞」型 オブジェクト 動詞 主語 動詞 第1文型SV
「動詞」型 オブジェクト 動詞 目的語 動詞 第3文型SVOからSが省略されている

「(?:is)?補語」型に関しては、オブジェクト(インスタンス)が主語に相当することが多く、「オブジェクト (?:is)?補語」という「主語 is 補語」に非常に近い記述となる。

「名詞」型も見られる。使用する言語によっては「プロパティ」だとか「アクセスメソッド」と呼ばれる機能が使われている。Javaでは慣習的にgetter/setterが用いられるので、「名詞」型ではなく「動詞・(?:副詞|目的語)」型となる。

終わりに

誰か、もっと厳密且つ網羅的に調べてないだろうか?