Erlang実験室:ビヘイビアを自分で定義する方法

Erlang/OTPでは、gen_server(Generic Server Behaviour)のような便利なフレームワークが用意されています。これは、ビヘイビア(behaviour)という概念に基づいています。ビヘイビアを使ったプログラムは、

  1. ビヘイビア実装モジュール(ライブラリ側)
  2. コールバック・モジュール(ユーザー定義側)

の2つのモジュールから構成されます*1

例えば、gen_serverのコールバック・モジュールでは、自分がgen_serverの規約に従うことを次の形で宣言します。


-behaviour(gen_server).
そして、必要なコールバック関数をエクスポートします。

-export([init/1, terminate/2, handle_call/3]).
-export([handle_cast/2, handle_info/2, code_change/3]).

さて、「ビヘイビアを自分で定義するにはどうしたらいいのだろうか?」と疑問だったんですが、gen_serverのソースを見たらすぐわかりました。例題として、状態マシンのフレームワークを作るとすれば、状態マシンのビヘイビア実装モジュールで次のように書きます。


-module(state_machine).

-export([behaviour_info/1]).

behaviour_info(callbacks) ->
[
% is_symbol(term()) -> boolean()
{is_symbol, 1},
% is_acceptable_symbol(State, term()) -> boolean()
% State = term()
{is_acceptable_symbol, 2},

% init() -> State
{init, 0},
% input(State, term()) -> NewState
{input, 2},
% is_final(State) -> boolean()
{is_final, 1}
];
behaviour_info(_Other) ->
undefined.

要するに、期待するコールバック関数達を {関数名, アリティ} の形で並べるだけです。形式上は、behaviour_info/1という関数を定義しますが、意味的にはある種のインターフェース宣言です。この宣言に対応する関数定義がコンパイルされ、モジュールのBEAMファイルに入ります。

コールバック・モジュール側で -behaviour(state_machine). と書くと、コンパイラはstate_machineモジュールのbehaviour_info/1を呼んで取得した情報をもとにチェックをします。ビヘイビアに宣言された関数がないと警告しますが、エラーにはなりません。

*1:2つ以上のモジュールで構成してもよいが、複雑化するから好ましくないだろう。