I am trying to refactor a module to incorporate protocols while still leaving part of the base module while handling polymorphism but am having some questions/challenges…
I have a module that handles a Strategy
, it has some basic methods like new
, setup
, update
. It also has a method called optimal
that should be polymorphic.
Function optimal
depends on the type of strategy
. Right now the module implements one particular type of Strategy
, let’s call this DominantStrategy
. But eventually, I want to create another called MixedStrategy
. I would like to reuse the base Strategy
methods new
, setup
, update
, while specifying the individual strategy’s implementation of optimal
separately.
defmodule Strategy do
defstruct ...
def new(args) do ... end
def setup(%Strategy{} = s, data) do ... end
def update(%Strategy{} = s, data) do ... end
def optimal(%Strategy{} =s) do ... end
end
Let’s say I were to create a protocol called Decision which declares optimal
defprotocol Decision do
def optimal()
end
Then I would create the code implementing the protocol like so:
defmodule DominantStrategy do
defstruct ...
def optimal(%DominantStrategy{} = strategy) do
...
end
defimpl Decision, for: DominantStrategy do
def optimal(%DominantStrategy{} = strategy) do
DominantStrategy.optimal(strategy)
end
end
defmodule MixedStrategy do
defstruct ...
def optimal(%MixedStrategy{} = strategy) do
...
end
defimpl Decision, for: MixedStrategy do
def optimal(%MixedStrategy{} = strategy) do
MixedStrategy.optimal(strategy)
end
end
So my question is: how do I make this work with the Strategy
module if the DominantStrategy
and MixedStrategy
structs are the same as the Strategy
struct? Is there a more FP way to handle this?
Specifically:
-
Do I eliminate the Strategy struct and hence the %Strategy{} = s pattern match?
-
Do I operate on the DominantStrategy struct and MixedStrategy struct generically in my top level methods like setup/update?
-
Does Strategy.new now return the specific Strategy implementation struct?
-
How to ensure the different structs (DominantStrategy, MixedStrategy) adhere to a common structure?
defmodule Strategy do
def new(args) do
case args.type do
:mixed -> MixedStrategy.new(args)
:dominant -> DominantStrategy.new(args)
_ -> raise “Error”
enddef setup(s, data) do ... end def update(s, data) do ... end def optimal(s) do Decision.optimal(s) end
end
Apologies in advance if this question type has been previously asked. A link would be appreciated.
If not, I would appreciate suggestions on the best way to go about this
PS. The presentation Well-Typed Elixir briefly touches on this.
– Thank you
Bibek