Is dead code not included in production releases? What about code from using macros?

Hey Forum, I’m trying to find some info about the compiler/BEAM. When a production release of an Elixir app is generated does it include dead code? Or can the compiler identify unused code (like it can identify unused variables from Erlang R6B onwards I believe) and not include it?

And what about if a whole module is unused? I’m more keen on understanding this from a metaprogramming perspective. Let’s assume we’ve got the following code:

defmodule MyMod do 
  use OtherMod
end

defmodule OtherMod do
  defmacro __using__ do
    ... some functions ...
  end
end

defmodule UnusedMod do
  defmacro __using__ do
    ... some functions ...
  end
end
  1. When I generated a production release, will the OtherMod be included? Since MyMod just receives the generated functions there’s no use for it to be there or can it be used for hot code reloading purposes?

  2. And what about UnusedMod (considering no other module is using it)?

  3. If the answer is to the above questions is that the code is always included then is there a way to not include dead/unused code?

Thanks!

4 Likes

All public functions and macros will be included in the release because you can load new code later or have dynamic code that uses the seemingly unused functions.

Elixir 1.3 will warn for (seemingly) unused functions unless you explicitly ignore them so you will know if you need to remove them.

6 Likes

Thank you for your reply @ericmj :slight_smile: so is there no way to not include or remove the beam files/source code from unused functions and modules during compile-time automatically, considering you have no intentions of ever loading new code?

I know it may sound like a weird thing to want to do but it’s for an experiment I’m working on :grin:

1 Like

Consider the following code:

defmodule Commands do
  def say_hello, do: IO.puts "Hello!"
  def say_goodbye, do: IO.puts "Goodbye!"
end

defmodule Runner do
  def run_command do
    module = IO.gets |> List.wrap |> Module.concat
    fun = IO.gets |> String.to_atom
    apply(module, fun, [])
  end
end

In this case it isn’t even possible in principle to determine wether the Command module can be removed or not as its use is completely determined at runtime. Now obviously my example program here is a bit contrived but you get the idea.

4 Likes

Yes thank you @benwilson512. I understand now :slight_smile:

2 Likes