Elixir and Behaviours by Ecto example

An Elixir behaviour is just a list of functions. A module that declares that it implements a particular behaviour must implement all of these functions.

I would say that behaviours are kind of interfaces from the OOP world.

Illustration by Peter Justin Gerard

Ecto uses behaviours for adding ability to create custom types. Let’s open ecto/lib/ecto/type.ex
@callback directive is used to define befaviours. It expects a function name and function specification.

defmodule Ecto.Type do
@callback type :: t
@callback cast(term) :: {:ok, term} | :error
@callback load(term) :: {:ok, term} | :error
@callback dump(term) :: {:ok, term} | :error
  ...
end

So if you want to use custom types then you should implement all of these 4 functions: type, cast, load and dump. Otherwise elixir will throw a compilation warning.

arc_ecto uses ecto’s custom type generation:

defmodule Arc.Ecto.Definition do
defmacro __using__(_options) do
definition = __CALLER__.module
    quote do
defmodule Module.concat(unquote(definition), “Type”) do
@behaviour Ecto.Type
def type, do: Arc.Ecto.Type.type
def cast(value) do
Arc.Ecto.Type.cast(unquote(definition), value)
end
def load(value), do: Arc.Ecto.Type.load(unquote(definition), value)
def dump(value), do: Arc.Ecto.Type.dump(unquote(definition), value)
end
end
  ...
end

@behaviour declares that Arc.Ecto.Definition implements Ecto.Type and then defines necessary functions.

Then you can use Arc’s custom type in the your app:

defmodule Spark.ImageUploader do
use Arc.Definition
use Arc.Ecto.Definition
end
defmodule Spark.Gallery.Image do
use Ecto.Schema
use Arc.Ecto.Schema
  schema "images" do
field :image, Spark.ImageUploader.Type
...
end
end

If you don’t clearly understand what is use and why it is used here, please read my previous post about macros.

That’s all for today. 
Thank you for reading this post!