40

In recent versions of Elixir, Access is no longer implemented as a protocol, but as a behaviour. From what I gather, this change was motivated by performance considerations in development mode.

Now, looking at the implementation, I wonder how this works internally and why this implementation was chosen. As we can see here, Access dispatches to a struct's module via the underlying map's "__struct__" key. AFAICS, this roughly works like OOP-style polymorphism. A few questions about this:

  1. Why is this faster?
  2. What are the downsides compared to Protocols? From what I can tell it is less extensible. Are there other?
  3. So far I have only seen behaviours in the context of stuff like GenServer, where the callback module is captured at initialization and kept in a process (At least I assume as much). Here, the Access behaviour grabs the callback module from the data. Would it even be possible to implement this behaviour for something that is not a struct?
  4. Is this kind of dispatch a common best practice in Erlang or Elixir when one is not interested in the added benefit that a Protocol would give?
Adam Millerchip
  • 20,844
  • 5
  • 51
  • 74
  • 2
    So, not an answer, but there is an Elixir core mailing list (on Google Groups) that may help to answer your questions. – Onorio Catenacci Nov 17 '15 at 01:47
  • Scanning over the subject there it looks like that might be not be right list. People on there are dicussion core language proposals, whereas my question is more a beginner's question regarding style. I don't really wanna spam the list with this. Good idea in principle, though. I might post this to a different elixir-related list. – MigratoryMonkeyMaster Nov 18 '15 at 22:38
  • I didn't get that from your question. Sounded like you wanted to know the reasoning behind the design. – Onorio Catenacci Nov 18 '15 at 22:40
  • 4
    Well if you want to know the decisions that went into the design then you want the Elixir Core Mailing list. I mean if at any point the reasoning behind using changing Access from a protocol to a behavior would be discussed and the other properties of that change--it'd be on that mailing list. – Onorio Catenacci Nov 19 '15 at 19:39
  • 3
    @MigratoryMonkeyMaster have you seen the related Github issue? Jose explains pretty well what the reasons were: https://github.com/elixir-lang/elixir/issues/2973 – Patrick Oscity Aug 03 '16 at 06:03
  • 1
    @PatrickOscity, thanks for pointing this out. It sure is an interesting read. But AFAICS the discussion is mostly concerned with the reasons for the change, and doesn't explain why this specific implementation was chosen, so it does not really address the core of my question. – MigratoryMonkeyMaster Aug 07 '16 at 20:51

1 Answers1

10

As you've already mentioned, Access's implementation was changed to use Behaviours instead of Protocols. The reasoning was performance.

  • Protocols are type/data based polymorphism, and are exclusive to Elixir. That means it lets you dispatch based on the data structure
  • Behaviours are a typeless mechanism that don't rely on a data structure, but the module as an argument. They're also built right into the Erlang/OTP ecosystem and are much more performant.

While Protocols do a lot of the heavy lifting for you when dispatching based on data types, they will still never be fast enough for Access because of the way they're implemented (consolidation),

So although you should always use Protocols when you need to tie some functionality to a data structure rather than a Module, Access is a special case.

Because the Access protocol relies on the code server in development and test mode (when protocol consolidation is not applied), we have heard multiple reports of the system suffering greatly in performance as the code server becomes a bottleneck with multiple processes.

This happens because the Access protocol ends up being invoked thousands of times and there isn't much we can do to improve it (in contrast to the Enumerable protocol where most of the list cases are inlined).

~ Jose Valim


Further Reading:

Community
  • 1
  • 1
Sheharyar
  • 73,588
  • 21
  • 168
  • 215