6
votes

To understand the Elixir language better, I wanted to try to do operator overloading, by adding an exclusive range operator, .... An example: 1...10 would then create a range from 1 up to but excluding 10 . (e.g. 1...10 == 1..9)

So, I looked up the definition of .., because the functionality of ... would of course be very similar.

Mmy module then became:

defmodule Sequences.Ranges do

  defmacro first ... last do
    case is_float(first) or is_float(last) or
         is_atom(first) or is_atom(last) or
         is_binary(first) or is_binary(last) or
         is_list(first) or is_list(last) do
      true ->
        raise ArgumentError,
          "ranges (first...last) expect both sides to be integers, " <>
          "got: #{Macro.to_string({:"Sequences.Ranges...", [], [first, last]})}"
      false ->
        case __CALLER__.context do
          nil -> quote do: Elixir.Range.new(unquote(first), unquote(last-1))
          _   -> {:%{}, [], [__struct__: Elixir.Range, first: first, last: (last-1)]}
        end
    end
  end

end

However, upon compiling this module, I get the following error:

== Compilation error on file lib/sequences/ranges.ex ==
** (CompileError) lib/sequences/ranges.ex:6: cannot invoke local .../1 inside match
    (stdlib) lists.erl:1353: :lists.mapfoldl/3

What am I doing wrong?

1

1 Answers

10
votes

There are only a limited number of infix operators that you can define in Elixir:

\\, <-, |, ~>>, <<~, ~>, <~, <~>, <|>, <<<, >>>, |||, &&&, and ^^^

They are predefined in the parser, but not implemented (or at least are not imported by default). This makes them available for custom implementations, but you can't create your own to add to this list unless you modify and recompile Elixir itself.

... is not one of them, so it won't work.

From the comment:

|||, &&&, ^^^, <<<, >>> and ~~~ are not by default imported, but are part of the default Elixir standard library's Bitwise module.

See http://www.rodneyfolz.com/custom-infix-functions-in-elixir/ for more details.