What are the scoping rule for Elixir alias?

What are the scoping rule for Elixir alias? Which directories will

alias A.B.C

look for? Will Elixir look for A.B.C up to the root directory?

The scoping rule says, that the alias A.B.C will have an effect from now on, until the current block gets closed, thats why you can define an alias in a function only.

So there is no directories involved that elixir would look at/in…

So in A.B.C, C refers only to C in that module and nowhere else?

A.B.C is a module name, alias A.B.C creates an alias, making C identical to A.B.C.

From the Programming Phoenix Book

accounts.ex

defmodule Rumbl.Accounts do

    alias Rumbl.Accounts.User

end

Rumbl.Accounts.User is located in .\accounts\user.ex relative to where accounts.ex is. So to me defmodule Rumbl.Accounts appears to have look for Rumbl.Accounts.User beyond its own directory?

Elixir will look up nowhere, as all modules are compiled to flat structure, so in the end, there is no directories, just modules. And alias is only naming alias, it doesn’t do any lookup (aka - you can alias non-existent module as well).

So it looks through all modules?

Module names and file paths are not related in Elixir. All files in the project (in the directories specified to the compiler) are compiled and a module can be in any path there. It is only a convention to have module names matching your directory hierarchy.

1 Like

No, it does nothing except providing shorter alias for the module name.

There is no looking up of sourcefiles or anything.

There is not even something that forces you to use folders or have files named in a certain way.

The compiler “remembers” all defmodules it has seen so far, and will therefore know which modules exist.

But still alias/2 does not verify if a given module exists that you want to alias. It just makes, that every occurence of User (based from the rumble example) will be expanded to Rumbl.Accounts.User before compiling into byte code.

1 Like

so its up to compiler to catch if the aliased Rumbl.Accounts.User does not exist?

Its up to the runtime.

Due to how the BEAM works, modules are lazyloaded, and only when the BEAM reaches the Rumbl.Accounts.User.foo() call the module is actually loaded and existence of the function checked.

So such a call will only fail at runtime. The compiler is long gone at that time.

2 Likes

This sounds like an Elixir disadvantage.

This sound like a requirement of being able to do hot code updates on the beam. Sure it’s nice to have the compiler help in such situations (maybe it’s even possible with a custom compiler), but having the ability to have code loaded at runtime provides useful things as well.

3 Likes

Between hot code updates and reliability the latter is more important don’t you think?

If it can’t load a module then the PID attempting to access it crashes, no other PID on the BEAM system dies, that PID can then be recreated by, say, it’s supervisor and rebuild state with new code as appropriate, or if you do indeed have a programming fault then prepare for your logs to be spammed, but everything else will still keep working along fine. :wink:

I.E. It’s very reliable.

Yes but it will be more reliable if the PID can find the module and wont need to recover (i.e. catch error at compile time).

Well if a PID can’t find a module, a programmer screwed up somewhere. :wink:

Besides, no such issues at release time anyway, all modules are pre-emptively loaded, it’s only during development that they are dynamically loaded.

How do you hide modules from other modules then?

You can’t hide, but you can obfuscate with really weird names. ^.^

It’s like Python in that way.

1 Like