Qqwy

Qqwy

TypeCheck Core Team

Why is Access a behaviour instead of a Protocol? When to use a Protocol instead of a Behaviour?

I am having some trouble understanding the difference between Behaviours and Protocols. This mostly is caused because the built-in Access functionality in Elixir is a Behaviour instead of a Protocol.

The odd thing is, that it seems that everything that a protocol does can be made using a Behaviour. Can someone shine light on what is going on?

Protocol:

  1. Someone defines a protocol using defprotocol, which has a name and one or multiple functions that need to be implemented (with the given arity). The first argument passed to these function implementations will always be the ‘thing’ that the Protocol is implemented on.
  2. In another module, someone defines an implementation for this protocol using defimpl.

Dispatching from the function call to the protocol implementations is automatic.

It is not possible to call the implementations directly on the final module, as they are secretly defined in another place that you cannot access yourself. Therefore, it also does not make sense to document the implemented functions.

Behaviours

  1. Someone defines a behaviour by just making a module and having multiple @callback statements in there, that take a spec; It seems that behaviours not only try to validate the arity of the callback implementations, but also e.g. the formats of the input/output data.
  2. To implement a behaviour, someone has to add use ModuleWithTheCallbackStatements to some module, and then simply define the callbacks of that behaviour in that module as functions.

Dispatching happens manually inside the module defining the behaviour (using e.g. for structs the module name inside the struct field); The callbacks may (using defoverridable) or may not be defined as functions in the module defining the Behaviour. This means that it is a lot easier to treat certain function inputs as ‘special’.

The implemented functions of a behaviour are simply defined and fully accessible and callable as normal functions. As such, they ought to be documented.


It seems to me that Behaviours are more flexible than Protocols. When is it a good idea to implement a Protocol rather than a Behaviour? Are there differences I’ve missed?

Most Liked

bbense

bbense

The @callback attribute doesn’t do as much as you might think, at best it just generates some compile time errors. You can actually use behaviours just fine w/o ever using the module that defines them.

A behaviour is just a promise that your module implements a function with given inputs.

A Protocol is a means for defining functions that potentially work for many different data types.

The way I think about it is that behaviours are for when you want to have a function for a single
set of args that potentially does different things. Protocols are for when you want to have a function that does the same thing for many different kinds of args.

You are correct that if you do enough hard work, you can probably implement a Protocol as a set of behaviours, but using Protocol does all the heavy lifting for you. This does not come for free though.

From my own work with Elixir I have some examples:

  • Write a function to find the documentation for a function in a Module in either Erlang or Elixir.

I wrote this as a behaviour. The arguments were exactly the same, but the underlying implementation was quite different. The idea was to have a list of Modules that implemented this behaviour and to call the function in each of the modules to find the documentation.

  • Create transformations of data structures without apriori knowledge of the data structure.

This is where Protocols shine because you can call the function defined in the Protocol recursively. Inspect is the example code to look at to really understand the power of Protocols.

Qqwy

Qqwy

TypeCheck Core Team

I asked @josevalim about it in the IRC group today directly. His reply:

(10:19:50 PM) josevalim: you only consolidate inside a project and after compilation
(10:20:03 PM) josevalim: this means all the access during compilation and in scripts still won’t be fast enough, which is a no-go

which is a very clear answer. Thank you very much, José! :heart_eyes:

michalmuskala

michalmuskala

Access was a protocol initially, but I think it was changed to a behaviour because of performance issues around protocol dispatch. It was simply too slow for something used as frequently as access.

Where Next?

Popular in Questions Top

beno
I will often find my self writing things similar to: case some_value do nil -> something() "" -> something() _ -> somethi...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
tduccuong
Hi, is there any work on GUI with Elixir, that is similar to Electron/Javascript? My idea is to bundle Phoenix and BEAM into a single se...
New
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New

Other popular topics Top

axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 48342 226
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 43757 214
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement