Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strange error reporting when importing module #4120

Closed
rohanpujaris opened this issue Dec 26, 2015 · 6 comments
Closed

Strange error reporting when importing module #4120

rohanpujaris opened this issue Dec 26, 2015 · 6 comments

Comments

@rohanpujaris
Copy link

I have made a repo with minimal code to generate a strange error. Error seems strange to me. It is generated when we write code as following.

defmodule My.MyModule do
  defmodule My.CustomModule do
  end

  defmacro __using__(_) do
    quote do
      import My.MyModule
    end
  end
end

Below is the repo link with minimal code: https://github.com/rohanpujaris/strangerror_elixir

I know that the thing that I tried is little weird and chances of others trying it is very rare. But it took me nearly 3hr to figure out what was the issue. If I haven't looked into error reported by the elixir, I would have solved it earlier. I feel the error is highly misleading.

When we compile code from above repo it will return below error.

== Compilation error on file lib/strangeerror.ex ==
** (CompileError) lib/strangeerror.ex:2: module My.MyModule.My.MyModule is not loaded and could not be found
    expanding macro: My.MyModule.__using__/1
    lib/strangeerror.ex:2: StrangeError (module)
    (elixir) expanding macro: Kernel.use/1
    lib/strangeerror.ex:2: StrangeError (module)

I was trying to use behaviours and I declared module inside another and after writing few lines of code I compiled the project and got above error. I have also raised question in stackoverflow http://stackoverflow.com/questions/34471538/unable-to-understand-import-via-using-macro-elixir-phoenix/ . But after finding out the reason, I feel like its better to report it here as an issue.

Also there is other thing which i felt was strange. When I transformed above code as below the error was gone.

defmodule My.MyModule do

  defmacro __using__(_) do
    quote do
      import My.MyModule
    end
  end

 defmodule My.CustomModule do
 end
end
@rohanpujaris rohanpujaris changed the title Strange error reporting when using Behaviours Strange error reporting when importing module Dec 26, 2015
@josevalim
Copy link
Member

Thank you for the report! When you define:

defmodule My.MyModule do
 defmodule My.CustomModule do
 end

  defmacro __using__(_) do
    quote do
      import My.MyModule
    end
  end
end

In order for My.CustomModule to work, Elixir will define an alias of My pointing to My.MyModule.My, so My.CustomModule becomes My.MyModule.My.CustomModule. That's how aliases and nested modules work, so not a bug. :)

@rohanpujaris
Copy link
Author

Thanks for the quick reply.
I understood little bit about how nested module work.
I am still confused. Why does the error says My.MyModule.My.MyModule is not loaded and could not be found. Please can you explain from where does elixir brings My.MyModule.My.MyModule into picture. Also why does above code work if I define nested module My.CustomModule below the __using__ macro. It shouldn't be position dependent. I believe that it might not be a bug, but I am quite worried about the strange error report. I think issue might probably my lack of knowledge with elixir. But still i would like to clear out above things.

@josevalim
Copy link
Member

It says My.MyModule.My.Module because your code now has an alias where My expands to My.MyModule.My. The order matters because aliases in Elixir are lexical (like imports and require).

@danhper
Copy link

danhper commented Dec 27, 2015

Maybe we could improve Kernel.defmodule documentation about nesting as it is clear by reading it that

defmodule Foo do
  defmodule Bar do
  end
end

will create an alias to Foo.Bar in the scope, but not that

defmodule Foo do
  defmodule Bar.Baz do
  end
end

will create an alias to Foo.Bar which can indeed be confusing for the above example.

@rohanpujaris
Copy link
Author

Thanks @josevalim for the explanation. Doubt cleared. I think I ignored the fact that aliase are lexically scoped after reading your first reply. Also i agree with @tuvistavie that improving documentation might help beginner like me.

@rohanpujaris
Copy link
Author

Ohh there is an example here http://elixir-lang.org/getting-started/alias-require-and-import.html for explaining alias. Sorry for the trouble. I also updated my answer in SO http://stackoverflow.com/questions/34471538/unable-to-understand-import-via-using-macro-elixir-phoenix/. Thanks @josevalim

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

3 participants