Serialization (Behaviours and protocols)

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)

I would implement as a Protocol just because of one reason: you can extend the serialization to user defined types, for example.

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.)

Yes, I think part of the question here is whether the functionality is all to be
supplied by the user/coder or not.

Maybe I will write a Serializable behaviour as well as a Serializer protocol to
illustrate how both work.

All comments welcome…

Hal