3 ms·
This code while cool is not very idiomatic or perhaps not something you’d see in production often. That’s ok, Joe loved to explore and experiment. The way it w
by rdtsc 3y ago
This code while cool is not very idiomatic or perhaps not something you’d see in production often. That’s ok, Joe loved to explore and experiment.
The way it works is that F is a closure. It contains some code but could have captured variables as well as it’s environment. Calling F() then executes the code and it will have access to the whole surrounding environment when F was created.
In Erlang we can send a closure across the network to another Erlang node. That can be used and is cool but you still need the module code referenced in the closure available on all nodes.
Long story short, in production code you’re right, we would just call the F module directly and pass its the arguments explicitly. This is more of a cool demonstration of possibilities.
- IggleSniggle 3y agoDoesn't this also allow hot-reloading on code update? You can update the code, and upon receiving, auto-reload it. So that "is just a closure" is adding a LOT of context (ie the entire codebase).
- toast0 3y agoYou could use this for hotloading: send every (relevant) process a message with a new closure to run, and they begin running it when they process that message, but BEAM provides other infrastructure for hotloading. For modules, BEAM can have two versions loaded: the current version, and an old version. When you make a fully qualified function call module:function(...), it will call the current version, but calls within the module stay within the same version. So if you load a module's new beam file, all processes that make fully qualified calls into that module get the new version. In case you're wondering, if you load a third version, any processes that still running in the first version get killed (you can check before you load a third version if you don't want that). It's idiomatic to write receive loops as loop(State) -> NewState = receive ... end, ?MODULE:loop(NewState). so that if a new version of the module is loaded, processes will update after they next receive a message. Then you might add a timeout or a heartbeat message to ensure the processes update in a reasonable timeframe. Or use gen_server which has the loop and calls your module so processes only linger in your old module while working on a request.
- rdtsc 3y agoIt can but it's somewhat orthogonal. What F really is, is a closure. Besides being a function it may also capture its surrounding variables. However, if in that closure it calls a function from some module like foo:bar(Var) the module foo bytecode still needs to be available on the remote node. There is a way to remotely load module bytecode to remote nodes but the just sending the closure F itself won't do it. It has to be done separately (https://www.erlang.org/doc/man/code#load_binary-3 https://www.erlang.org/doc/man/code#load_binary-3 is one way to do it or the shell prompt's nl(...) function does the same).