Understanding @behaviour

This particular file is a behaviour.

And this is implementing it

Now my question is, Why do I even need to use a behaviour? If I were to do this for the second link ^^ it will still work.

defmodule Phoenix.Transports.V2.WebSocketSerializer do
  @moduledoc false

  # @behaviour Phoenix.Transports.Serializer

  alias Phoenix.Socket.{Reply, Message, Broadcast}

  @doc """
  Translates a `Phoenix.Socket.Broadcast` into a `Phoenix.Socket.Message`.
  """
  def fastlane!(%Broadcast{} = msg) do
    data = Poison.encode_to_iodata!([nil, nil, msg.topic, msg.event, msg.payload])
    {:socket_push, :text, data}
  end
.
.
.

So what’s the point of using behaviour? The Phoenix.Transports.Serializer just defines functions without function body and leaves it to other module to implemente that function’s body.

What am I missing?

You can think of it like a contract that is visibile to the compiler.

Right now the behaviour defines a single function fastlane!/1. What if, in the future, that behaviour changed and added a new function. You would now have fastlane!/1 and foo/2. The compiler will let you know that you have a module that does not fully comply with the contract that has been written.

2 Likes

@behaviour is just compiler annotation that helps you when you miss some functions required by the caller, it doesn’t change anything else.

2 Likes

The @behaviour redirects the dependencies allowing for swappable implementations of the interface. This means the Phoenix framework application code can depend on the Serializer behaviour/interface/contract instead of the WebSocketSerializer directly. So if there were a situation where you need a special serializer, you wouldn’t need to fork Phoenix or wait for them to change it. We would just need to implement another Serializer and configure Phoenix to use it.

1 Like

FYI:

3 Likes

thanks . You know what links to share :slight_smile: