0

If I had a mix task such as the following defined in hello.ex, it runs fine.

defmodule Mix.Tasks.Hello do
  use Mix.Task
  def run(_), do: IO.puts "hello"
end

But this doesn't seem possible in a "hello.exs" type file? Or is there a way to have a mix task without the ".ex" extension.

Adam Millerchip
  • 20,844
  • 5
  • 51
  • 74
Nona
  • 5,302
  • 7
  • 41
  • 79

1 Answers1

1

I am not sure what do you mean by “without compilation.” Elixir is indeed a compiled language, it’s unable to execute anything without compilation.

In addition to the Elixir file extension .ex, Elixir also supports .exs files for scripting. Elixir treats both files exactly the same way, the only difference is in intention. .ex files are meant to be compiled while .exs files are used for scripting. When executed, both extensions compile and load their modules into memory, although only .ex files write their bytecode to disk in the format of .beam files.
https://elixir-lang.org/getting-started/modules-and-functions.html#scripted-mode

mix is an external application to your code. It requires a .beam file to execute it, or it has to load the compiled script into its process memory.

So, technically you might do somewhat like

defmodule Mix.Tasks.Hello do
  use Mix.Task
  def run(_), do: IO.puts "hello"
end

defmodule Mix.Tasks.Wrapper do
  use Mix.Task
  def run(task) do
    Code.compile_file("hello.exs")
    Mix.Task.run(Module.concat(task))
  end
end

But why? What would be wrong with having the task as .ex file?

Also, you might achieve something similar with a help of Code.compile_string/2 to compile the task and load it into mix process’ memory, but again, that’s not how it’s intended to be used.

Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160
  • Edited ?...I meant ".ex" file not "compiled". One thing that seemed to be happening was that if I changed a function in a ".ex" file, say Hello#hello_world/1 (e.g., changed the output of IO.puts/1), I would have to manually recompile to get the changes to register. If I made a ".exs" script, the changes seemed to register. – Nona Aug 27 '19 at 04:32
  • Eh. You are not supposed to change `mix` tasks frequently :) Use arguments if you need to have a configurable behavior. Also, if you need to manually recompile something, you should fix your configuration (possibly in `mix.exs`.) When properly configured, the project does not require manual recompilation, no matter what. – Aleksei Matiushkin Aug 27 '19 at 04:35
  • But still, `foo.exs` _gets recompiled_, but you don’t get `.beam` file back and the changed bytecode is living inside your process (`iex` or whatever.) `mix`, being a different process / application has to recompile the script on its own _to get the bytecode into its memory_. There is no magic. – Aleksei Matiushkin Aug 27 '19 at 04:37
  • If I made a change to the mix task function in a ".ex" file, shouldn't Elixir pick up on the changes and recompile when I run "mix hello whatever task"? I was having to essentially remove the .beam file(s) to get Elixir to recompile. – Nona Aug 27 '19 at 04:38
  • With `Code.compile_string/2` I mentioned above you might get the bytecode of anything inside your currently running process instantly, but I doubt it’s a good way to write maintainable code. – Aleksei Matiushkin Aug 27 '19 at 04:38
  • “I was having to essentially remove the .beam file(s) to get Elixir to recompile.”—that should not happen. Make sure your task source code is located under the directory specified in `mix.exs` as a path to be compiled. – Aleksei Matiushkin Aug 27 '19 at 04:40