「Erlang実験室:例外的値とバリアント型データ」において、Erlangでは例外の使用が少ない気がすると言いました。その理由として、「やたらに自由度が高いバリアント型があるからだろう」と推測しました。同じ理由により、レコード型も意外に使われてない気がします(また「気がします」で統計的裏付けはない)。
例えば、person型レコードは次のように定義できます。(以下の定義はこのままコンパイルできますが、フィールドの型は単なる注釈で実際的意味を持ちません。)
-record(person, {
name::string(),
age::integer(),
mail_address::string()
}).
このレコード定義と同等な定義は、他のプログラミング言語でも書けます。例えばCなら:
struct Person {
wchar_t *name;
short int age;
wchar_t *mail_address;
};
ですが、こんな定義をしないで、単なるタプルをperson型データと思って使うことが多いようです。その理由は:
- タプルの項目数が2つや3つなら、フィールド名がなくても順番や意味をおぼえられる。
- しちめんどくさいレコードの構文を使うより、直接に、リテラルやパターンマッチングを使うほうが楽。
それとですね、レコードは定型のタプルなので、Erlangの“やたらに自由度が高いバリアント型”のメリットが失われるんですよね。具体的に言うと、Erlangでは、person型を次のように定義することができます。(言語仕様で定義できるわけではなくて、習慣的な型記述構文。)
Person = ( atom() | string() |
{(atom() | string())} |
{(atom() | string()), integer()} |
{(atom() | string()), integer(), string()} )
これだと、{"tonkichi", 27, "tonkichi@tozai-travel.example.jp"} に対して次のような省略ができます。
- メールアドレスが不要なら、{"tonkichi", 27}
- 年齢も不要なら、{"tonkichi"}
- タプルにしなくてもいい "tonkichi"
- アトムだっていい tonkichi
- タプルの項目もアトムでよかった {tonkichi, 27}
実に自由気ままです。そんなデータ使ったら処理が鬱陶しいだろうって? そうでもないんですよ。次のようなパターンマッチングで場合分けできます。
case Person of
Name when is_atom(Name) ->
% アトムのとき
Name when is_list(Name) ->
% 文字列(リスト)のとき
{Name} ->
% 1項目のタプルのとき
{Name, Age} ->
% 2項目のタプルのとき
{Name, Age, MailAddr} ->
% 3項目のタプルのとき
end
でもね、可読性やドキュメンテーションの観点からは、使えるならできるだけレコードを使ったほうが望ましいと思いますよ。