[Elixir]@behaviour and @callback

簡単なWebフレームワークを作ってみようと、Plugtrotを読んでいると、いたるところで @behaviour と描かれているものがありました。

GenServer なんかを use した時にOTPとしての振る舞いを、対象モジュールに与えることができました。そこで使われている Behaviour は把握していたのですが、この @ のアノテーションはパッと思い出すことができなかったので、メモがてら。

Elixir 1.2.xの時点が対象です。結論から書いておくと、この @behaviourBehaviour のことで、2.0では削除される Behaviour の代わりに推奨されているものです。

自身で定義したBehaviourに関して、以下のように @callback で定義したものを、 @behaviour で読み込んで使うという用途で使われます。ここで、読み込んだ先で @callback しているものを def で定義していない場合、 warning が表示されます。

例えば、以下の MyModuleMyGenServer の直前のコメント箇所のような。


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.BuilderPlug.Parsers なんかでも使われています。

他に、

https://github.com/elixir-lang/elixir/blob/v1.2/lib/elixir/lib/module.ex

を見てみるといくつかのattributesが存在することもわかります。これらは、以下の preprocess_attribute/2postprocess_attribute\2 で定義されている通りです。

ここによると以下が使われているそうな。その詳細はmoduleのドキュメントを参照ください。

@on_load
@behaviour
@file
@before_compile
@after_compile
@on_definition
@type
@typep
@export_type
@opaque
@callback
@macrocallback

@doc
@typedoc
@moduledoc

なるほどね。

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.