When using defdelegate, does the compiler skip the call to the local function to only call the target function?
Also the documentation for defdelegate mentions “to another module” but can it not be “to another function of the same module” also?
OK, so then the documentation should be updated because “other module” is misleading. Just saying.
But the heart of my question is: is there 2 calls or only 1? In other words, is there a “penalty” for delegating or is the compiler brilliant enough to only call the target function?
Because of the possibility of hot code loading I don’t think function calls that go across module boundaries can be elided. However due to last call optimization it won’t be allocating any additional stack frames or having to shuffle registers, so the overhead will be minimal.
The good thing about open source is, of course, you can see exactly what it does at https://github.com/elixir-lang/elixir/blob/master/lib/elixir/lib/kernel.ex#L4755-L4819 (which is basically what I described above). I think the documentation describes pretty well what it does - but it doesn’t describe how it does it and I’m personally not sure thats the purpose of the documentation.
Of course if you want to delegate without re-exporting the function then importing the function would be more appropriate and it does dispatch directly to the target module.
In general I wouldn’t worry about the performance of defelegate. Function calls in Elixir are very fast and low overhead. You should be benchmarking a real system to get an idea of where you should spend time optimizing.
The Erlang compiler is very conservative with inlining, because it affects semantics for hot code upgrades and exceptions, without improving performance much. It won’t inline calls between modules, and only performs inlining within a module if you ask it to via directives like @compile :inline.