I’ve been thinking about the topic of behaviours and protocols for several weeks,
basically a cycle of “think, discuss, code, take notes, repeat.”
Someone suggested that serialization would be a good example of something
to implement with a behaviour; someone else said that it was a natural example
for a protocol.
I think it depends on what you mean. Here is my very simple example of a Serializable behaviour. It couldn’t be rewritten as a protocol, really. But
maybe looking at the problem differently, it could be? After all, simply saying
“serialization” doesn’t fully define the problem.
Still seeking good examples of a custom-defined behaviour and a protocol
to show their similarities and differences.
defmodule Serializable do
@callback load(String.t) :: any
@callback dump(any) :: String.t
end
defmodule MyCollection do
defstruct [:foo, :bar]
def new(x, y) do
%MyCollection{foo: x, bar: y}
end
@behaviour Serializable
def load(str) do
[x, y] = String.split(str, "\n")
MyCollection.new(String.to_integer(x), String.to_integer(y))
end
def dump(item) do
"#{item.foo}\n#{item.bar}"
end
end
x = MyCollection.new(3,5)
dumped = MyCollection.dump(x)
y = MyCollection.load(dumped)
Behaviours and Protocols are very similar. Basically, Protocols are just a wrapper around Behaviours that decide what module to call the Behaviour’s functions on based on the data (the first argument) that is passed in.
In this case, your Serializable behaviour could more properly be called Serializer, if you want it to specify a way to serialize something. You could then have a JSON Serializer, an XML Serializer, an Erlang Binary Format Serializer, etc.
This works, but assumes that you’re able to serialize everything that is passed to your functions. If you instead want to allow the authors of some data types (structs) to alter how these data structured are serialized, then it is more useful to use a protocol.
Observe, for instance, the difference between Ecto.Type (a behaviour implementation of loading/dumping data from database to custom structs, given a schema.) and Ecto.DataType (a protocol that can be overridden for custom structs to be converted to/from a database-specific value, not needing a schema.)