lessless

lessless

For example I have multiple currencies

dollar.ex

defmodule Multicurrency.Currency.Dollar do
  @enforce_keys [:amount]
  defstruct [:amount]

  @type t :: %__MODULE__{
    amount: integer()
  }

  @spec new(number()) :: Multicurrency.Currency.Dollar.t()
  def new(amount) do
    %__MODULE__{amount: amount}
  end
end

franc.ex

defmodule Multicurrency.Currency.Franc do
  @enforce_keys [:amount]
  defstruct [:amount]

  @type t :: %__MODULE__{
    amount: integer()
  }

  @spec new(number()) :: Multicurrency.Currency.Franc.t()
  def new(amount) do
    %__MODULE__{amount: amount}
  end
end

They are basically the same and I wonder if it’s possible to have some kind of a generic struct or a protocol for structs that will define common keys and allow to pattern match on the instances of that struct:

defmodule Multicurrency.Currency do
  @enforce_keys [:amount]
  defstruct [:amount]

  @type t :: %__MODULE__{
    amount: integer()
  }

end
defmodule Multicurrency.Currency.Franc do
  @impl Multicurrency.Currency

  @spec new(number()) :: Multicurrency.Currency.t()
  def new(amount) do
    %__MODULE__{amount: amount}
  end
end
def equals?(Multicurrency.Currency{amount: a1},  Multicurrency.Currency{amount: a2}) do
    a1 == a2
  end

Does it even make sense?

Showing Posts 1 to 10

OvermindDL1

OvermindDL1

You can with the built-in Protocol if you handle all currency types within your singular protocol implementation or double-dispatch out to another protocol for the specific currency type (which should be fine).

If you truly want to protocol dispatch over an instance binding (I.E. full match) then the built-in Protocol cannot do that but ProtocolEx can (and it can be faster than Elixir protocols as well). But I don’t recommend it until you actually Need proper match semantics.

lessless

lessless OP

What about pattern-matching in functions? Or that is a totally different strategy, i.e. not an Elixir-way?

OvermindDL1

OvermindDL1

That’s what I meant in my first option, pattern match in the functions of the implementation (or the direct calls, however you are doing it). This is perfectly fine if you don’t need it to be extensible via plugins or so.

axelson

axelson

Scenic Core Team

Yeah but you can only pattern match on the map keys, so you can’t be certain you’re getting a currency, you may be just getting a struct that happens to have an amount type.

OvermindDL1

OvermindDL1

You can match on the struct type as well.

axelson

axelson

Scenic Core Team

But you can’t match on multiple struct types at once, correct?

How would you combine these into one clause?

def add(%Multicurrency.Currency.Franc{} = currency) do ... end

def add(%Multicurrency.Currency.Dollar{} = currency) do ... end
blatyo

blatyo

Conduit Core Team

Not the prettiest, but:

def add(%currency_type{} = currency) 
when currency_type in [Multicurrency.Currency.Franc, Multicurrency.Currency.Dollar] do 
end

But you could turn part of that into a guard.

lessless

lessless OP

That’s what I’m talking about. It feels that this can be solved in a more straightforward manner.

blatyo

blatyo

Conduit Core Team

If you’re on the newest erlang you could do.

defguard is_currency(currency) 
when :erlang.map_get(:__struct__, currency) in [Multicurrency.Currency.Franc, Multicurrency.Currency.Dollar]

def add(currency) when is_currency(currency) do
end
dom

dom

I realize it’s side-stepping the question, but this really sounds more like a use case for a record: {:currency, “HKD”, amount}. Then add, equals?, etc. are trivial to write.

What are you trying to achieve with the structs?

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
kszambelanczyk
Hello! Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app. I creat...
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
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
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

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
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews