Exception from alias ordering. Is this expected?

Hello, I noticed something strange and I don’t know if it is a bug or it is expected. I created a small project. It has 3 .ex files.

lib/resolver/alch_test.ex

defmodule AlchTest.Resolver.AlchTest do
  def resolve(:resolved) do
    "It resolved"
  end

  def resolve(:unresolved) do
    "Didn't resolve"
  end
end

lib/resolver/alert.ex

defmodule AlchTest.Resolver.Alert do
  def alert() do
    "Alerting!!!"
  end
end

and

lib/web/alch_test.ex

defmodule AlchTest.Web.AlchTest do


  alias AlchTest.Resolver.AlchTest
  alias AlchTest.Resolver.Alert

  def start() do
    AlchTest.resolve(:resolved)
    |> IO.puts


    AlchTest.resolve(:unresolved)
    |> IO.puts

    Alert.alert()
    |> IO.puts

  end
end

And when I try in iex I get an exception

iex(5)>  AlchTest.Web.AlchTest.start
It resolved
Didn't resolve
** (UndefinedFunctionError) function AlchTest.Resolver.AlchTest.Resolver.Alert.alert/0 is undefined (module AlchTest.Resolver.AlchTest.Resolver.Alert is not available)
    AlchTest.Resolver.AlchTest.Resolver.Alert.alert()
    (alch_test) lib/web/alch_test.ex:15: AlchTest.Web.AlchTest.start/0

When I switch the aliases order in lib/web/alch_test.ex it works

lib/web/alch_test.ex

defmodule AlchTest.Web.AlchTest do


  alias AlchTest.Resolver.Alert
  alias AlchTest.Resolver.AlchTest

  def start() do
    AlchTest.resolve(:resolved)
    |> IO.puts


    AlchTest.resolve(:unresolved)
    |> IO.puts

    Alert.alert()
    |> IO.puts

  end
end
iex(5)> recompile
Compiling 1 file (.ex)
:ok
iex(6)>  AlchTest.Web.AlchTest.start
It resolved
Didn't resolve
Alerting!!!
:ok
1 Like

I would very much avoid naming modules with a repeated part like this.

Your iex code snippet starts on line 5, can we see what you had before that?

2 Likes

I don’t have the original iex session open but here is a replay

[~/tmp/alch_test]
[voger@toshiba:22:55:15]$ iex -S mix
Erlang/OTP 20 [erts-9.0.1] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:10] [hipe] [kernel-poll:false]

Compiling 1 file (.ex)
warning: function AlchTest.Resolver.AlchTest.Resolver.Alert.alert/0 is undefined (module AlchTest.Resolver.AlchTest.Resolver.Alert is not available)
  lib/web/alch_test.ex:15

Interactive Elixir (1.5.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> AlchTest.Web.AlchTest.start
It resolved
Didn't resolve
** (UndefinedFunctionError) function AlchTest.Resolver.AlchTest.Resolver.Alert.alert/0 is undefined (module AlchTest.Resolver.AlchTest.Resolver.Alert is not available)
    AlchTest.Resolver.AlchTest.Resolver.Alert.alert()
    (alch_test) lib/web/alch_test.ex:15: AlchTest.Web.AlchTest.start/0
iex(1)> recompile
Compiling 1 file (.ex)
:ok
iex(2)> AlchTest.Web.AlchTest.start
It resolved
Didn't resolve
Alerting!!!
:ok
iex(3)>

I though that the problem had something to do with both the host module and the aliased module having the same ending. Now that you mention it I noticed the repeated part.

1 Like

Think about it…

You define an alias for AlchTest to expand to AlchTest.Resolver.AlchTest, then you want to have an alias Alert to AlchTest.Resolver.Alert which gets expanded to AlchTest.Resolver.AlchTest.Resolver.Alert because of the previous alias.

Despite of what @benwilson512 already said (try to avoid having beginning and end of an alias identical), you could do it like this to circumvent:

alias AlchTest.Resolver.{AlchTest, Alert}

or this:

alias AlchTest.Resolver
alias Resolver.AlchTest
alias Resolver.Alert
5 Likes

Thanks. It didn’t occur to me all this aliases chain even after that AlchTest.Resolver.AlchTest.Resolver.Alert.alert/0 line.

1 Like