bibekp

bibekp

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”
    end

    def 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

Showing Posts 1 to 3

bbense

bbense

It really sounds like you want a behaviour, not a protocol.

Protocols are for calling the same function on different data types.

Behaviours are for a custom implementation of a function for each module. In essence a behaviour is a promise that your module implements a function of name X with arity Y. So that if I pass in
the module name to another module it can use

Kernel.apply(module, :optimal, [strategy])

bbense

bbense

In the case of Structs, they are really just Maps with a special key that identifies the module that they are associated with.

iex> foo = 1..3
iex> bar = Map.get(foo, :“__struct__”)
iex> Kernel.apply(bar, :“range?”, [foo]) == Range.range?(foo)

bibekp

bibekp OP

Thanks there @bbense.

I guess more than passing around different types I am more passing around modules – hence the use of behaviors.

This older post helps to distinguish between the different types of polymorphic activity

My only minimal requirement would be for another module to abstract away the custom behaviors so my client code doesn’t need to worry about DominantStrategy vs. MixedStrategy

— All posts loaded —

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews