Erlang’s Dynamism
This is more verbose answer to @bubbafat twitt-question. It started lkie this:
- @bubbafat: Functions used by spawn to start a process must be exported. Why doesn’t erl compiler error when this is missed? #erlang
- @danielllo: @bubbafat ‘cos it is possible to define and load new modules later on during runtime in #erlang
- @bubbafat: @danielllo Thx. Do you mean redefining the module at runtime or that the func might resolve in a different module loaded later? #erlang
- @danielllo: You have many ways of referencing #erlang module:function not known at compile time.
-
- you can load the precompiled module at later time from a path not being provided to compiler.
- you can use M:F(Args) function invocation in #erlang, any of M, F, Args being variables dynamically referencing module, function and argument list.
- you can construct erlang AST tree programmaticaly, compile it at runtime and load the resulting beam.
- you can acheive the p.3 result using a helper tools such as LFE, Smerl or “Dynamic” module generation with compile-time macros
- … and I’m sure there is more
Categories: erlang, programming
I know you didn’t mean to get sucked into a long discussion when you replied to my tweet - I appreciate that you’ve taken as much time as you have to respond. If you have a few more minutes I still have one question.
I understand how the dynamic nature of Erlang can allow resolving the function later on when the module name is provided (M:F) or when the name is a variable.
But when it’s a non-qualified local function name I’m still not seeing it - perhaps I am misunderstanding Erlangs scope or lifetime rules.
Example:
-module(foo).
-export([start/0]).
function() ->
…
start() ->
PID = spawn(foo, function, []),
…
–
In that specific case - how is the reference resolvable later to something other than foo:function()? I did not indicate a module name and it’s not a variable … and using an atom doesn’t make sense there (to me, anyway). So it seems like it must be a function from the locally defined module (in which case validating that the function is exported should be trivial).
I absolutely get that if the spawn had been:
PID = spawn(foo, Variable, []),
or
PID = spawn(foo, othermodule:function, []),
then resolving later is not just a feature - it’s mandatory to ensure that if the other module wasn’t loaded, or changed, etc that the call is updated.
The only case I currently see (I’ve only been learning Erlang for a few days so there is a lot I don’t see yet) is the case where the current module (foo) changes (potentially redefining foo:function).
But in that case wouldn’t the existing process continue to run with the old definition of the foo module (where the reference is still unambiguous)?
Anyway - thanks again.
On the way to work I decided the way Erlang does it is right.
The example I gave was too simple. Once processes begin starting other processes and we create a fun that spawns a process and start calling that fun dynamically … well … resolving late is important.
When the function was not in the export list the compiler gave me a warning that the function was never called. I should have heeded it.
I’m glad to hear that. Anyway always happy to help