I’ve read in several blog posts and here in the forum about the fact that Erlang supports constants folding. But it seems things are not that simple. Suppose you have this code (simplified from a real project):
defmodule MyModule2 do
import Phoenix.HTML, only: [sigil_e: 2]
defp operator_key(), do: "my-operator-key"
defp value_key(), do: "my-value-key"
def f() do
~e"<%= operator_key() %> - <%= value_key() %>}"
end
end
When you compile and disassemble it, you get:
-file("lib/forage_web/experiments/experiments.ex", 44).
-module('Elixir.MyModule2').
-compile([no_auto_import]).
-export(['__info__'/1, f/0]).
-spec '__info__'(attributes | compile | functions |
macros | md5 | module | deprecated) -> any().
'__info__'(module) -> 'Elixir.MyModule2';
'__info__'(functions) -> [{f, 0}];
'__info__'(macros) -> [];
'__info__'(Key = attributes) ->
erlang:get_module_info('Elixir.MyModule2', Key);
'__info__'(Key = compile) ->
erlang:get_module_info('Elixir.MyModule2', Key);
'__info__'(Key = md5) ->
erlang:get_module_info('Elixir.MyModule2', Key);
'__info__'(deprecated) -> [].
f() ->
{safe,
[begin
__@5 = [begin
__@1 = <<>>,
[__@1 | case operator_key() of
{safe, __@2} -> __@2;
__@3 when erlang:is_binary(__@3) ->
'Elixir.Plug.HTML':html_escape_to_iodata(__@3);
__@4 -> 'Elixir.Phoenix.HTML.Safe':to_iodata(__@4)
end]
end
| <<" - ">>],
[__@5 | case value_key() of
{safe, __@6} -> __@6;
__@7 when erlang:is_binary(__@7) ->
'Elixir.Plug.HTML':html_escape_to_iodata(__@7);
__@8 -> 'Elixir.Phoenix.HTML.Safe':to_iodata(__@8)
end]
end
| <<"}">>]}.
operator_key() -> <<"my-operator-key">>.
value_key() -> <<"my-value-key">>.
The operator_key()
and value_key()
are constants, so the case statements here:
[__@1 | case operator_key() of
{safe, __@2} -> __@2;
__@3 when erlang:is_binary(__@3) ->
'Elixir.Plug.HTML':html_escape_to_iodata(__@3);
__@4 -> 'Elixir.Phoenix.HTML.Safe':to_iodata(__@4)
end]
and here (both of which can be resolved at compile time):
[__@5 | case value_key() of
{safe, __@6} -> __@6;
__@7 when erlang:is_binary(__@7) ->
'Elixir.Plug.HTML':html_escape_to_iodata(__@7);
__@8 -> 'Elixir.Phoenix.HTML.Safe':to_iodata(__@8)
end]
should hasve been optimized away. Why aren’t they? Is there anything I’m not seeing?
Aside: what motivated me to look at this? Well, I have some keys that are shared in the same module (and across modules, too) and I wanted to gather them into the same place. Unfortunately, even if the compiler optimizes the case statements way, it’s not reasonable to expect the the ~e
sigil will be able to optimize away the 'Elixir.Plug.HTML':html_escape_to_iodata(X)
calls at compile time So I’ll just embed the constants in the string anyway.