Is there any difference (in generated byte-code/performance/etc) between assigning the returned value of a function to _
_ = func()
and just calling it
func() # not assigned to anything, just called
?
I’ve noticed that it’s often done the first way (_ = func()) in some erlang code bases that I’ve been reading, like here, and I also remember this blogpost about some compiler optimizations like
The compiler will be able to optimize your code greatly, for example not creating the result [of a comprehension] if you don’t need it.
And to be honest, in my opinion, _ = fun() or any variant thereof is more readable than just fun().
However, I just ran the following test in IEx:
code1 = quote do
defmodule Foo do
def fun() do
:ok
end
def test() do
fun()
nil
end
end
end
code2 = quote do
defmodule Foo do
def fun() do
:ok
end
def test() do
_ = fun()
nil
end
end
end
compiled1 = Code.compile_quoted(code1)
compiled2 = Code.compile_quoted(code2)
compiled1 == compiled2
# false
Turns out they are not the same. Interesting! There probably is a way to make the compiled bytecode inspectable, giving us an idea of what the actual difference between the two is, but I don’t know how to do that right now.
I was talking about this with @michalmuskala, who said that the final bytecode that is executed probably is the same, but since the bytecode also contains debug information that is different when you write the non-compiled code differently, they indeed are not equal.
I’ve not been able to uncompile the generated BEAM code to something readable myself yet. I know there are ways to do it (Michal shared this with me), but I have not got them to work thus far.
I don’t know how you access it from the elixir compiler but you can get the erlang compiler to return the BEAM assembler it generates. Quite illuminating. It is a bit easier to read than the output of :erts_debug.df/1.
If you’re referring to 'S' for Elixir it should be ERL_COMPILER_OPTIONS="'S'" elixirc foo.ex. For reasons beyond me that causes a compilation error and puts the wrong module in foo.ex.S.
I thought :erts_debug.df/1 was easier to read in this case anyways.