Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you import a custom module defined in another file?

Tags:

elixir

a.exs:

defmodule A do
  def greet, do: IO.puts "hello"
end

b.exs:

defmodule B do
  import A
  def say_hello, do: greet
end

Result:

~/elixir_programs$ iex b.exs
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]

** (CompileError) b.exs:2: module A is not loaded and could not be found

~/elixir_programs$ tree .
.
├── a.exs
├── app1.exs
├── b.exs
....

For that matter, how do you use the qualified name to call a function defined in another module:

b.exs:

defmodule B do
  def say_hello, do: A.greet
end

~/elixir_programs$ iex b.exs
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]

Interactive Elixir (1.6.6) - press Ctrl+C to exit (type h() ENTER for help)

iex(1)> B.say_hello
** (UndefinedFunctionError) function A.greet/0 is undefined (module A is not available)
    A.greet()

Okay, this works:

iex(1)> c "a.exs"
[A]

iex(2)> B.say_hello
hello
:ok
like image 601
7stud Avatar asked Dec 06 '22 11:12

7stud


2 Answers

There are two main things one should understand about Elixir: it is a compiled language and it differentiates between compiled files and scripts (the latter are also compiled, but they do not compile automatically by mix by default.)

Compiled languages, unlike scripting languages (ruby, python, javascript, ...) are supposed to pass two stages before the functionality becomes available: the files should be compiled and then the runtime (read: Erlang VM) should be loaded. One cannot just require 'foo' as we do in ruby or import bar as we do in python and expect the thing to work.

Elixir provides handy helpers to do a compilation in runtime in Code module, including but not limited to: Code.require_file/2 and Code.compile_file/2.

When using mix, only the non-script files, having an extension .ex, are compiled by default. That is why test files, being scripts (.exs) do not ever mess up with the runtime.

That said, there are four main options to make it work:

  1. Use mix project and files named a.ex and b.ex. That way you’ll get everything on hand, compiled, by running iex -S mix.
  2. Use Code.require_file("a.exs") from your b.exs to explicitly require a.exs.
  3. Tell iex to compile (if necessary) and load all the files by running iex -r a.exs -r b.exs.
  4. Do the compilation manually as you do in your answer.
like image 192
Aleksei Matiushkin Avatar answered Mar 07 '23 03:03

Aleksei Matiushkin


If all the .exs files are in the same directory, you can run iex -r *.exs and that will load all the .exs into your iex session. You could also load the files one by one via iex -r a.exs -r b.exs

like image 22
Alex Koutmos Avatar answered Mar 07 '23 04:03

Alex Koutmos