簡単なWebフレームワークを作ってみようと、Plugやtrotを読んでいると、いたるところで @behaviour と描かれているものがありました。
GenServer なんかを use した時にOTPとしての振る舞いを、対象モジュールに与えることができました。そこで使われている Behaviour は把握していたのですが、この @ のアノテーションはパッと思い出すことができなかったので、メモがてら。
Elixir 1.2.xの時点が対象です。結論から書いておくと、この @behaviour は Behaviour のことで、2.0では削除される Behaviour の代わりに推奨されているものです。
- ドキュメント
- https://github.com/elixir-lang/elixir/blob/v1.2/lib/elixir/lib/module.ex
- https://github.com/elixir-lang/elixir/blob/v1.2.3/lib/elixir/lib/behaviour.ex#L1
- Behaviorは、Elixir 1.2.3 からdepricatedになった。
自身で定義したBehaviourに関して、以下のように @callback で定義したものを、 @behaviour で読み込んで使うという用途で使われます。ここで、読み込んだ先で @callback しているものを def で定義していない場合、 warning が表示されます。
例えば、以下の MyModule や MyGenServer の直前のコメント箇所のような。
| defmodule ModuleExample do | |
| @type opts :: tuple | atom | integer | float | [opts] | |
| @callback my_behaviour(opts) :: :ok | :error | |
| # deprecatedだが、 `use Behaviour` と `defcallback` を使うことができる | |
| @callback init(opts) :: :ok | :error | |
| @callback call() :: :ok | :error | |
| end | |
| # sample.exs:13: warning: undefined behaviour function call/0 (for behaviour ModuleExample) | |
| # sample.exs:13: warning: undefined behaviour function init/0 (for behaviour ModuleExample) | |
| defmodule MyModule do | |
| @behaviour ModuleExample | |
| def my_behaviour(:ok), do: :ok | |
| def my_behaviour(:error), do: :error | |
| def my_behaviour(other), do: IO.inspect(other); :ok | |
| end | |
| # sample.exs:27: warning: undefined behaviour function code_change/3 (for behaviour :gen_server) | |
| # sample.exs:27: warning: undefined behaviour function handle_call/3 (for behaviour :gen_server) | |
| # sample.exs:27: warning: undefined behaviour function handle_cast/2 (for behaviour :gen_server) | |
| # sample.exs:27: warning: undefined behaviour function handle_info/2 (for behaviour :gen_server) | |
| # sample.exs:27: warning: undefined behaviour function init/1 (for behaviour :gen_server) | |
| # sample.exs:27: warning: undefined behaviour function terminate/2 (for behaviour :gen_server) | |
| defmodule MyGenServer do | |
| @behaviour :gen_server | |
| end |
これが、例えば、Plugだとこのリンク先 のように定義されていて、こんな感じでcallbackが用意されています。
defmodule MyPlug do @behaviour Plug def init(opts), do: opts def call(conn, _opts), do: conn end
この他にも、 Plug.Builder や Plug.Parsers なんかでも使われています。
他に、
https://github.com/elixir-lang/elixir/blob/v1.2/lib/elixir/lib/module.ex
を見てみるといくつかのattributesが存在することもわかります。これらは、以下の preprocess_attribute/2、 postprocess_attribute\2 で定義されている通りです。
ここによると以下が使われているそうな。その詳細はmoduleのドキュメントを参照ください。
@on_load
@behaviour
@file
@before_compile
@after_compile
@on_definition
@type
@typep
@export_type
@opaque
@callback
@macrocallback@doc
@typedoc
@moduledoc
なるほどね。