binarypaladin

binarypaladin

Why doesn't Elixir support standard operator overloading?

I’m working on a project right now that makes heavy, heavy use of Decimal. I just hit bug today where >= was used instead of Decimal.compare/2 and it’s not the first time I’ve seen this happen.

Additionally, Decimal has some nice convenience methods (as Java-esque as they are) such as eq?/2 and gt?/2. This is nicer than having to drop into compare/2.

It seems like protocols could totally make operator overloading a thing. I would obviously really like to just be able to do %Decimal{} + %Decimal{} and have it work like Decimal.add/2. And, coming from a Ruby background, I’m, used to overloading a lot.

These are just functions, yes? I can pipe with Kernel.+/2 and Kernel.==/2.

Having said all that, this seems quite deliberate and I feel like with as much as I have read I would have come across the answer but… I don’t know. And either my Googling skills are poor or I’m asking the wrong question.

Why doesn’t Elixir support standard operator overloading?

Marked As Solved

billylanchantin

billylanchantin

If you want to go down the rabbit hole of why Elixir has made the choices it has, I suggest the following elixir-lang-core discussions:

It’s a lot of back and forth, but it was pretty eye opening for me. In particular, I think this comment from José sums up the situation well:

There’s even an experimental implementation of a comparable protocol in that thread:

But the consensus seemed to be that such an implementation would be unwieldy in practice.

Also Liked

binarypaladin

binarypaladin

Yeah, the reasons have been spelled out well in this thread. I honestly asked because if there is something I have come to expect from this language, it’s that the decisions always seem to have really solid reasoning, even where it doesn’t jive with my personal tastes. I figured from the start there were legit philosophical and technical reasons for it and looking through the mailing lists made that clear enough.

Yeah. Honestly, I kinda wish I hadn’t even brought that up. It was just me talking about how I like the way Ruby can be written, especially for a non-programmer. I don’t think Elixir would be better for it, but I also think it’s still fine to appreciate what other languages can do. It turned into… a fixation I didn’t intend in the conversation.

I think anyone who has been programming for very long knows how important precision is with dates. We all have horror stories, lol. The system I am working on right now is a real beast if you’re not extremely careful about bloody time zones!

This was the main thing I came for because that was the bug I hit. No warning. No nothing. And I know why it’s that way.

And hey, since I have you here… I love Elixir! It’s what I use professionally. I was a long time Rubyist (about 12 years) and I made the move. I still miss some bits but there’s no going back. You and your team have done such a good job with both the language and community. I can’t tell you how much it’s improved my work and me as a programmer.

I am continuously humbled by your ability to address even hostile comments with incredible wisdom and humility. I appreciate you taking the time to comment. Seriously.

josevalim

josevalim

Creator of Elixir

We don’t have the concept of primitives, as in those languages, but integer and float are built-in types and decimal is a custom one. So there is a clear demarcation here. In any case, if I could, I would support decimal + integer, but we can’t do it today without making it slower for all cases and without breaking guard semantics. The shortest way around this is to have decimal as a native VM type.

Other than that, I am very glad to not have date + 1.days, because there isn’t anything arithmetic about it. For example, it is not guaranteed that (date + duration) - duration == date. I do like 1.days though, as a mechanism to express durations, but I would be 90% as a happy if we had Date.shift(date, months: 1, days: 10) in Elixir (PRs are welcome, I consider this to be the last calendar feature missing in Elixir).

Finally, the hope is that once we have the type system, we will warn if you give a struct to any >, >=, <, and <=. It is pretty much a language pitfall that I hope we can address more reliably.

sodapopcan

sodapopcan

You could do something like this:

defmodule MyDecimal do
  defmacro __using__(_) do
    quote do
      import Kernel, except: [+: 2, -: 2, ...]

      def left + right do
        Decimal.add(left, right)
      end

      def left - right do
        Decimal.sub(left, right)
      end

      # ...
    end
  end
end

For me, the lack of operator overloading is part of what makes Elixir a good dynamic language as it still cares about types. It’s also part of (all of?) what is enabling the possibility of strong arrows (if we get some static typing). If you looked at a language like OCaml it goes even further. + only adds ints, you need to use +. to add floats! And you must explicitly cast one side if you want to add a float to and int.

I don’t know if this is the exact reason Elixir doesn’t overload, though.

billylanchantin

billylanchantin

CompareChain might help with some of your use cases (shameless plug: I’m the author). I had similar headaches working with DateTime structs. It’s easier to read code like:

  • left <= right vs
  • DateTime.compare(left, right) != :gt.

CompareChain is a sort of middle ground where you can write this:

import CompareChain

a = Decimal.new(1, 42, 0)
b = Decimal.new(1, 42, -1)
compare?(a >= b, Decimal)

It’s not perfect, but I find that it helps.

dimitarvp

dimitarvp

Used to think so myself (had 6.5y with Rails before I moved to Elixir) but honestly, my day is not ruined for having to write this instead:

NaiveDateTime.add(date, 2, :day)

:person_shrugging:

Also don’t forget that time is very finicky, we still have leap seconds and summer/winter time jumps. There are situations, just in the right two dates of the year, where adding a few hours to a datetime will lead to ambiguous times, e.g. check this out: Timex.AmbiguousDateTime — timex v3.7.11

Having arithmetic operators for something that can jump back or forth beneath your feet I would find suboptimal and unpredictable. I’d prefer patter-matching on the result of a datetime operation, including the ambiguous results.

Where Next?

Popular in Questions Top

dotdotdotPaul
Okay, I'm having a heck of a time trying to figure out how to best handle the validation of belongs_to associations in Ecto. I'm sure I'...
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
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
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
Fl4m3Ph03n1x
Background Let’s assume I have a typical GenServer that receives messages as requests, does some operation in a DB and returns responses....
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
Exadra37
Sometimes I want to check if the input into a function is not a blank string. My first approach: defmodule Example do def do_stuff(s...
New
Mooodi
Given a string, how can I get access to its character by index? Enum.at("my_string", 2) doesn't work. Or rather, not char, but a substr...
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

Other popular topics Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
sergio
I couldn’t find any guides that worked well with Phoenix 1.6.0 and esbuild. I hope this helps people test the waters and eases you into t...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 45766 226
New
polypush135
As many of you may have realized by now (sorry for all the posts here) I’ve been working on a db problem where I’m trying to aggregate a ...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
New
magnetic
Hey :wave:t3: Elixir community, I’ve been learning Elixir, and working on some side projects. My editor of choice is VSCode, and althoug...
New

We're in Beta

About us Mission Statement