Polymorphism

Protocol

Protocol is a manchanism for dispatching behavior based on data type, kind of like interface in other languages.

defprotocol Speak do
  def speak(data)
end

defmodule Dog do
  defstruct [:name]
end

defimpl Speak, for: Dog do
  def speak(%Dog{name: name}), do: "#{name} says woof!"
end

Speak.speak(%Dog{name: "Rex"})
# "Rex says woof!"

Elixir's Protocol is conceptually similar to Clojure's protocol:

(defprotocol Speak
  (speak [this]))

(defrecord Dog [name])

(extend-type Dog
  Speak
  (speak [{:keys [name]}]
    (str name " says woof!")))
    
(let [rex (->Dog "Rex")]
  (speak rex))

Behavior

Behaviour is a formal way to define interfaces that modules should implement.

defmodule MyBehaviour do
  @callback hello(String.t()) :: String.t()
end
defmodule MyModule do
  @behaviour MyBehaviour

  @impl MyBehaviour
  def hello(name), do: "Hello, #{name}"
end

Behaviour conformance is checked at compile time. The compiler will warn if any required callback is missing or arity doesn't match.