denna
Combining Protocol and Behaviour - how to call a a function on a Module that inherits the function from another Module?
I am trying to provide a way to create something like inheritance.
i want to be able to call a a function on a Module that inherits the function from another Module. Is the following the most straightforward way?
defprotocol Proto do
@spec foo(t()) :: charlist()
def foo(item)
end
defmodule SpecializedProto do
@callback info() :: charlist()
end
defimpl Proto, for: Atom do
@impl true
def foo(item) do
apply(item,:foo,[item])
end
end
defimpl Proto, for: SpecializedProto do
@impl true
def foo(item) do
apply(item,:info,[])
end
end
defmodule Test do
@behaviour SpecializedProto
def info(), do: "test"
defdelegate foo(x), to: Proto.SpecializedProto
end
Proto.foo(Test)
Most Liked
al2o3cr
This isn’t what protocols are for, and probably (I have not run it) doesn’t work like you really want.
For the above declaration to make sense, you’d need to be calling Proto.foo with a %SpecializedProto{} struct.
Protocols solve a particular problem: how to make a function handle many data types that aren’t known by the function’s original authors. A simple example from the stdlib is String.Chars, which defines to_string and is used by the kernel to_string function.
Without protocols, the only way to write String.Chars.to_string would be with many heads:
defmodule String.Chars
# non-protocol version
def to_string(v) when is_integer(v), do: ...
def to_string(v) when is_map(v), do: ...
def to_string(v) when is_list(v), do: ...
# etc
end
However, having custom formatting for user-defined structs would require adding new clauses to String.Chars.to_string which isn’t supported (or particularly practical).
Protocols let you do that kind of dispatching because defimpls don’t have to be supplied all-at-once like defs.
A general suggestion when prototyping something like this: start out by writing a straightforward implementation that does what you want and uses the components you’re creating. Copy-paste code FREELY during this initial part, but try to keep changes to copied code clearly labeled.
Once you’ve got things sketched out enough, only then start thinking about how to DRY things out / reduce boilerplate / do macro-fu / etc. It will be a lot more obvious where you need flexibility like protocols with working code.








