All of that makes sense. Protocols are literally behaviours with custom dispatching rules, so your impression that they impose some rules in favor of some features is correct.
You are also correct that Flow could use protocols and the reason we didn’t use them is we are not ready to expose the Window materialization API.
That’s the only part I don’t agree with. If you are already using a protocol then you already have a behaviour. Protocols do not allow default implementations because it generating coupling between protocols and implementations. We already have the coupling at the specification level, which is the point of protocols, but moving it to the implementation level means that changing the default implementation of a protocol will affect all implementations that depend on it.
The __using__+defoverridable trick can also be really harmful for augmenting the protocol. For example, imagine the protocol has 2 functions today. In the future, you add a third function but you also provide a default implementation for it. Now implementations have no idea there is a third function! Maybe they would like to implement it but the default implementation means no warning is emitted. Situation can be even worse on libraries pre-1.0: what if you decide to rename a function? With the default implementation, they won’t even know something was renamed and developers will be unaware the contract even changed, wondering for hours why their implementation isn’t being called.
While we cannot solve the first problem (the one the developer will not get a warning if new functions are added to the protocols), we can solve the second one. Instead of:
# Inside quote
def add(a, b) do
a + b
end
defoverridable add: 2
# Inside implementation
def add(a, b) do
# ...
end
We should have:
@overridable true
def add(a, b) do
a + b
end
# Inside implementation
@override true
def add(a, b) do
# ...
end
This way if you override something that was not marked as overridable or something that does not exist, you will get a warning. It also improves code readability, because anyone reading the code will see the whole purpose of add/2 is to override a callback. Previously readers of the code could be left wondering why there is an add/2 function in the first place.
I want to send a proposal for the new overridable system after Elixir v1.4 is out. So you need to be aware of the limitations of the current system today.






















