apoorv-2204

apoorv-2204

How do you handle enums in your codebase?

The Issue of Enums in Elixir

Elixir doesn’t have a native enum construct, so we usually rely on atoms, strings, or macros to represent named constants.

Observed Issues

String vs Atom:

Some contexts (like pattern matching or internal logic) prefer atoms, while others (like database fields or API responses) require strings.
Maintaining consistency across both can be cumbersome — I eventually prefer enums as strings for simplicity.

Compile-Time vs Runtime Checks:

We can emulate enums using function calls, but not within guards or compile-time contexts.
Macros can provide compile-time validation, but require the require keyword, which reduces simplicity.
There’s no built-in mechanism for enforcing enum constraints at both compile and runtime.

Questions:

How do you handle enums in your codebase?

Do you rely purely on atoms and type specs, or use macro-based libraries for safer compile-time checking?

Would a lightweight, language-level enum-like abstraction make sense for Elixir?

Most Liked

mudasobwa

mudasobwa

Creator of Cure
defmodule MyEnum do
  defmacro sigil_MYENUM({:<<>>, _, [value]}, [] = _modifiers) do
    case __CALLER__.context do
      :match ->
        if value in ~w[one two], do: value, else: raise(value)
      _ ->
        if value in ~w[one two], do: value, else: raise(value)
    end
  end
end

defmodule TestMyEnum do
  import MyEnum

  def test(value) do
    IO.puts(~MYENUM[one])
    IO.puts(~MYENUM[two])

    case value do
      ~MYENUM[one] -> IO.puts("ONE MATCHED")
      ~MYENUM[two] -> IO.puts("TWO MATCHED")
    end

    ~MYENUM[three]
  end
end

This example is a bit overfilled with some shenanigans, but it’d give you a great start.

garrison

garrison

Actually, one thing that does bother me is that there are a few different ways to implement constants and they all have different tradeoffs. I think this is a bit unintuitive.

@my_enum [:first, :second, :third]
def my_enum, do: [:first, :second, :third]
defmacro my_enum, do: [:first, :second, :third]

The third one is the only way to do pattern matching on constants from another module, yet that is the one which is not documented.

garrison

garrison

Of course for database fields Ecto does support enums. For other stuff I generally use atoms and pattern matching. I wouldn’t necessarily be opposed to a native Enum construct but pattern matching and a public constant for enumeration gets you pretty much all of the way there.

I think the type system will help a lot, here (and Dialyzer already helps a bit). I always liked the string literal types in TS. We generally use atoms, but it’s the same idea. Types are most useful for tooling rather than type-checking (i.e. autocomplete).

Schultzer

Schultzer

You forgot sigils

Where Next?

Popular in Troubleshooting Top

alexlanderzander
Hello everyone, I’m working on a blockchain project in Elixir and I’m implementing some of the core cryptography in a Rust NIF using Rus...
New
chocolatedonut
Besides (over)logging every code-path leading to Repo.insert_all, is it possible to make Postgrex and/or ecto_sql log the exact, failing ...
New
Ferenc
I have installed it on Phoenix 1.8.1 (without authentication or other packages and got 2 problems). I had to set up things manually the ...
New
mooreryan
In a project I’m working on, I cannot get tests with breakpoints or pry working. Here is an example in a new mix project. Create a fresh...
New
wktdev
I tried to learn Elixir a few years ago and stopped. I am trying again. In the code below I have a GenServer that is started by a Superv...
New
jdj_dk
Hi everyone. I’m trying to setup a small cluster with three nodes. I’m using libcluster as I have before. But my nodes doesn’t have a us...
New
harmon25
Hi All, I am bumping into a weird issue with an umbrella app while upgrading to latest Elixir 1.19.x + otp28. A couple apps in the umbr...
New
runyonave
We have been stuck on this for a few days now and I am really not sure what could be missing. I can get chromic_pdf to work perfectly fin...
New
michaelterryio
Hey, I’ve got a project with several path dependencies. Some are phoenix apps, but this likely isn’t relevant. I don’t fully understand...
New
arnoldwolfe
I’ve been unable to deploy apps for over a week now due to the following error. It all started when Github has issues with GitHub Actions...
New

Other popular topics Top

joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 record...
New
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
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
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
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
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
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
josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New

We're in Beta

About us Mission Statement