Last active
September 5, 2019 13:25
-
-
Save stefanluptak/f5588b1b04836f2464071ddc7731932d to your computer and use it in GitHub Desktop.
Behaviour vs. Protocol in Elixir
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Counter do | |
@type t :: %__MODULE__{count: integer()} | |
defstruct count: 0 | |
def transform(counter, %transformation_module{} = transformation) do | |
transformation_module.transform(counter, transformation) | |
end | |
end | |
defmodule Counter.Transformation do | |
@callback transform(Counter.t(), term()) :: Counter.t() | |
end | |
defmodule Increment do | |
defstruct [:by] | |
@behaviour Counter.Transformation | |
@impl Counter.Transformation | |
def transform(%Counter{} = counter, %__MODULE__{} = increment) do | |
%{counter | count: counter.count + increment.by} | |
end | |
end | |
defmodule Multiply do | |
@enforce_keys [:by] | |
defstruct [:by] | |
@behaviour Counter.Transformation | |
@impl Counter.Transformation | |
def transform(%Counter{} = counter, %__MODULE__{} = multiply) do | |
%{counter | count: counter.count * multiply.by} | |
end | |
end | |
# usage | |
counter = %Counter{count: 3} | |
increment = %Increment{by: 4} | |
Counter.transform(counter, increment) == %Counter{count: 7} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Increment do | |
defstruct [:by] | |
end | |
defmodule Multiply do | |
defstruct [:by] | |
end | |
defmodule Counter do | |
@type t :: %__MODULE__{count: integer()} | |
defstruct count: 0 | |
def transform(%__MODULE__{} = counter, %Increment{} = increment) do | |
%{counter | count: counter.count + increment.by} | |
end | |
def transform(%__MODULE__{} = counter, %Multiply{} = multiply) do | |
%{counter | count: counter.count * multiply.by} | |
end | |
end | |
# usage | |
counter = %Counter{count: 3} | |
increment = %Increment{by: 4} | |
Counter.transform(counter, increment) == %Counter{count: 7} # true |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Counter do | |
@type t :: %__MODULE__{count: integer()} | |
defstruct count: 0 | |
def transform(%__MODULE__{} = counter, %transformation_module{} = transformation) do | |
protocol_module = Module.concat(Counter.Transformation, transformation_module) | |
protocol_module.transform(counter, transformation) | |
end | |
end | |
defprotocol Counter.Transformation do | |
def transform(counter, transformation) | |
end | |
defmodule Increment do | |
defstruct [:by] | |
defimpl Counter.Transformation do | |
def transform(%Counter{} = counter, %@for{} = increment) do | |
%{counter | count: counter.count + increment.by} | |
end | |
end | |
end | |
defmodule Multiply do | |
defstruct [:by] | |
defimpl Counter.Transformation do | |
def transform(%Counter{} = counter, %@for{} = multiply) do | |
%{counter | count: counter.count * multiply.by} | |
end | |
end | |
end | |
# usage | |
counter = %Counter{count: 3} | |
increment = %Increment{by: 4} | |
Counter.transform(counter, increment) == %Counter{count: 7} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Counter do | |
@type t :: %__MODULE__{count: integer()} | |
defstruct count: 0 | |
end | |
defprotocol Counter.Transformation do | |
def apply(transformation, counter) | |
end | |
defmodule Increment do | |
defstruct [:by] | |
defimpl Counter.Transformation do | |
def apply(increment, %Counter{} = counter) do | |
%{counter | count: counter.count + increment.by} | |
end | |
end | |
end | |
defmodule Multiply do | |
defstruct [:by] | |
defimpl Counter.Transformation do | |
def apply(multiply, %Counter{} = counter) do | |
%{counter | count: counter.count * multiply.by} | |
end | |
end | |
end | |
# usage | |
counter = %Counter{count: 3} | |
increment = %Increment{by: 4} | |
Counter.Transformation.apply(increment, counter) == %Counter{count: 7} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment