I am just working through Dave Thomas' book and am currently exploring Protocols in Elixir. I know I can fallback to a generic protocol implementation with @fallback_to_any true
. For example:
defprotocol Caesar do
@fallback_to_any true
def encrypt(string, shift)
def rot13(string)
end
defimpl Caesar, for: BitString do
def encrypt(string, shift) do
# implementation for binary
end
def rot13(string) do
# implementation for binary
end
end
defimpl Caesar, for: List do
def encrypt(string, shift) do
# implementation for character list
end
def rot13(string) do
# implementation for character list
end
end
defimpl Caesar, for: Any do
def encrypt(string, shift) do
# generic implementation
end
def rot13(string) do
# generic implementation
end
end
However in the above case, basically every implementation of rot13/1
would look like this:
def rot13(string) do
Caesar.encrypt(string, 13)
end
Still, I currently have to repeat this in every implementation, which seems utterly wrong. Is there a way to share rot13/1
across all implementations of Caesar
?
So I found this question about delegation in implementations. It made me wonder whether defdelegate
works inside protocols and indeed it does! So a possible solution to this is as follows:
defmodule Caesar.Shared do
def rot13(string) do
Caesar.encrypt(string, 13)
end
end
defprotocol Caesar do
def encrypt(string, shift)
defdelegate rot13(string), to: Caesar.Shared
end
defimpl Caesar, for: BitString do
def encrypt(string, shift) do
# implementation for binary
end
end
defimpl Caesar, for: List do
def encrypt(string, shift) do
# implementation for character list
end
end
I'm still interested in other answers. Maybe there is still a better, more idiomatic way to do this directly inside the protocol definition.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With