lessless

lessless

Is it possible to declare a generic type?

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?

Most Liked

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Is that easier than %Currency{denomination: "HKD", amount: amount}?

I think the flaw with @lessless’s plan honesty is making a struct per denomination.

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Right. This is readily apparent if two protocols both require a function called call/2 for example. If you implement this with monkey patching or even inheritance you’re gonna run into issues because the class can only have a single #call method. However you can easily create two different protocol implementations for two different protocols that both have a call function because you always pass the data structure to the protocol, so there’s no ambiguity.

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
LostKobrakai

LostKobrakai

This should hopefully not be the message and I’d like to give some context. Many people question the elixir community whether or why there’s no static typing capabilities or at least something more rigorous than dialyzer, while being unaware that many people did work and are working in that space. But to my understanding there has not yet been found a good way to type the message passing capabilities for processes on the beam in a manner of favorable tradeoffs. There are also a few other less critical things to consider like e.g. hot code reloading.

Therefore it’s less a matter of not accepting or implementing feedback, but rather one of the community being aware of the requests and their benefits – but not having a solution – while the question of why this is not in elixir pops up regularly. There are many people who’d like to see more static typing in elixir and piece by piece the core team does seem to add the things to the compiler that they can.

LostKobrakai

LostKobrakai

Just a few links in regards to type systems in elixir and on the beam in general:

Where Next?

Popular in Questions Top

JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New

Other popular topics Top

senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 35421 110
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New

We're in Beta

About us Mission Statement