How many functions do you have?

A while back this question popped up in one of the many places where the Erlang community gathers, I think it was IRC:

How many functions do you have in your Erlang node?

As an answer, Craig posted this beauty:

1> length([{M,F,A} || {M,_} <- code:all_loaded(), {exports,Fs} <- M:module_info(), {F,A} <- Fs]).
2531
2> length([{M,F,A} || {M,_} <- code:all_loaded(), {exports,Fs} <- M:module_info(), {F,A} <- Fs]).
2539
3> {ok,2}.
{ok,2}
4> length([{M,F,A} || {M,_} <- code:all_loaded(), {exports,Fs} <- M:module_info(), {F,A} <- Fs]).
2628
Original from KissPNG

What’s going on here?

As usual, it’s better if you try understanding this by yourself. If you are up for the challenge, just boot up an Erlang VM and try to figure out what’s happening.

I’ll jump straight to the answer instead: Erlang has Dynamic Code Loading. As the docs point out…

The code server loads code according to a code loading strategy, which is either interactive (default) or embedded. In interactive mode, code is searched for in a code path and loaded when first referenced. In embedded mode, code is loaded at start-up according to a boot script. This is described in System Principles.

Alright, mystery solved: The new functions that appear once we evaluate the list comprehension a second time are loaded right there because they’re needed to evaluate the first list comprehension and print its result.

Let’s see if our observations match with that hypothesis. And just for fun, let’s do it in Elixir. First, let’s see if the same behavior is experienced in iex, too:

iex(1)> length(for {m, _} <- :code.all_loaded, {:exports, fs} <- m.module_info(), {f, a} <- fs, do: {m, f, a})
4239
iex(2)> length(for {m, _} <- :code.all_loaded, {:exports, fs} <- m.module_info(), {f, a} <- fs, do: {m, f, a})
4319
iex(3)>

Excellent! Now let’s see what functions are those new ones. Actually, since modules are loaded all at once (i.e. code server doesn’t load individual functions, it loads the entire module when it needs it), let’s see which modules are the new ones. To do that, we need to start a new VM, of course, and then…

iex(1)> ms = :code.all_loaded; length(ms)
172
iex(2)> new_ms = (:code.all_loaded -- ms)
[
{Inspect.Integer, 'path/to/Elixir.Inspect.Integer.beam'},
{Inspect.Algebra, 'path/to/Elixir.Inspect.Algebra.beam'},
{Inspect.Opts, 'path/to/Elixir.Inspect.Opts.beam'},
{Inspect, 'path/to/Elixir.Inspect.beam'}
]
iex(3)>

And there you have it, the new modules are no others than the ones required to print out 172 on the screen.


Spawnfest 2018 is Around the Corner

We are less than a month away from Spawnfest 2018, the annual international online FREE 48-hour-long hackathon for the BEAM community!

For this year we have an amazing panel of judges (Miriam Pena, Kenji Rikitake, Juan Facorro, René Föhring, Tristan Sloughter and Andrea Leopardi), some great sponsors (Erlang Solutions, AdRoll, Peer Stritzinger, ScrapingHub, 10Pines, Fiqus and LambdaClass) and, more importantly… some AMAZING PRICES!! You can win tickets to conferences, gift cards from Amazon, books, GRiSP boards, GoPros, headsets, ElixirCasts.io, t-shirts…

Build your team, register at our website and join us on November 24th and 25th! It will be great!

If you don’t have a team, you can register your self in our super find-a-team machine™️ and we will help you find one.

And if you don’t have an idea, check our list of suggestions.