呼び出そう」をもとに加筆・補正し、文章を整えました。function_exported?/3でビヘイビアの関数の実装を確かめるビヘイビアが実装されたモジュールから、それらの関数を呼び出すときは、予めfunction_exported?/3によりその関数が備わっているかどうか確かめます。つぎのようなFooビヘイビアを実装したFooImplモジュールがあるとします。endend呼び出す関数からは、つぎのようにfunction_exported?/3で引数のモジュールの関数がエクスポートされているか、つまりFooビヘイビアが実装されているかを確認してから呼び出します。これでまったく問題のないコードにみえるかもしれません。endendcall_foo(FooImpl)しかし、このコードは、mixから起動したときに動作しない場合があります。動作しないのかドキュメントのfunction_exported?/3の項には、つぎのような注意書きがあります。引数のモジュールが予めロードされていない場合、function_exported?/3はモジュールの読み込みはしません。関数が実装されていない場合だけではなく、モジュールがまだロードされていないときもfalseが返されるのです。VMにロードされていなければなりません。それを理解するには、Erlangがモジュールをロードする戦略を知る必要があります。VMのデフォルトは後者)。アプリケーションを起動したときに、すべてのモジュールがロードされます。最初にそのモジュールの関数を呼び出したときに、そのモジュールがロードされます。対話モードになります。そのため、前掲のコードを動かしたとき、FooImplモジュールの関数をまだどれも呼んでいなければ、function_exported?/3はfalseを返してエラーになるのです。他方で、先に実行されたコードがFooImplモジュールの関数を呼び出していると、function_exported?/3の戻り値はtrueとなり、正しくmod.foo()が呼ばれます。mixから起動したときは、どのコードをとおったかによって動作は変わってしまいます。これが「動作しない場合」があると述べた理由です。Distilleryで生成すると、デフォルトで組み込みモードになります。モジュールのロードを確かめるドキュメントのfunction_exported?/3の項は、Code.ensure_loaded/1の参照を促します。引数のモジュールがロードされているかどうか確かめて、結果がまだであればロードしてくれる関数です。つぎのようにCode.ensure_loaded/1の呼び出しを書き加えると、ビヘイビアのモジュールの読み込みが実行されます。endendcall_foo(FooImpl)もっとも、モジュールの読み込みは、何らかの理由で失敗するかもしれません。その場合にはつぎのfunction_exported?/3がfalseを返して、結局ビヘイビアを実装していないというエラーになります。この例ような簡単なコードでしたら、これで済むこともあるでしょう。株式会社gumiのエンジニアによる技術記事公開やDrinkupイベントなどの技術者交流を行うアカウントです。Blog株式会社gumiのエンジニアによる技術記事を公開しています。Blog@gumigumiのエンジニアによる技術記事を公開しています。[Follow]して最新情報をご入手ください。