4 ms·
In erlang the code is compiled to an intermmediate representation for a virtual machine, BEAM (erlang virtual machine), usually the functions you define are ver
by manthideaal 7y ago
In erlang the code is compiled to an intermmediate representation for a virtual machine, BEAM (erlang virtual machine), usually the functions you define are very short and in this case the BEAM code is sent over the network, so the universal server receives the compiled or transpiled code and executed it using the BEAM. You can compare it to a lisp server in which you send the program as a list, in lisp code is data.
- OskarS 7y agoCan these functions be closures that close over a bunch of data that isn't hard-coded into the functions? I don't know erlang, but imagine the erlang version of this python code: def adder(v): return lambda x: v + x Can I then send the result of (say) "adder(5)" over the network and have it work?
- manthideaal 7y agoSee theses two answers: https://stackoverflow.com/questions/39396491/is-there-a-way-to-send-a-closure-to-remote-node-in-erlang https://stackoverflow.com/questions/39396491/is-there-a-way-... https://stackoverflow.com/questions/39255471/what-is-the-point-of-spawnnode-fun-on-erlang-if-node-has-to-have-the-same-mo https://stackoverflow.com/questions/39255471/what-is-the-poi...
- toast0 7y agoSure: On a erlang shell in node A, do: register('test', self()). receive F -> ok end. (this gives the shell a registered name, and then waits for a message) On a debug shell on node A do: AddrFactory = fun (X) -> fun (Y) -> Y + X end end. {test, NodeA} ! AddrFactory(5). Then, back on node A, do F(10). And you'll get 15 For more fun, you could have node A send the value to go into the closure, etc. NodeA is something like 'demo@hosta.example.org' NodeA would be started with something like erl -name demo@hosta.example.org -setcookie demo and NodeB started like erl -name demo@hostb.example.org -setcookie demo
- OskarS 7y agoThat is extremely cool.
- dnautics 7y agoIt's also crazy insecure, so you shouldn't use this sort of stuff unless you really know what you're doing and you have full control over the inputs and outputs, that includes owning your network in depth. I don't want to discourage you from using erlang and Elixir, because the beam is amazing, plenty of very lucrative companies (like bet365) do, just, be aware of things you might versus might not run in an actual prod situation.
- toast0 7y agoI mean, it's not that it's crazy insecure. It's that the security model is totally different. In distributed erlang, access to any node is effectively access to all of the nodes; it's best to consider the distributed system as one computer from a security point of view. Do not run distributed Erlang with nodes you don't trust. Do not run distributed Erlang on a network you don't trust (VPN/TLS can help).
- dnautics 7y agowell specfically `binary_to_term` on arbitrary untrusted data is insecure, but you could of course pass `[safe]` in. Just, read the docs and heed the warnings.
- dnautics 7y agoin elixir, open a new shell: variable = 5 lambda = &(&1 + variable) File.write!("pickle", :erlang.term_to_binary(lambda)) close terminal, open new shell unpickled = "pickle" |> File.read! |> :erlang.binary_to_term unpickled.(5) yields 10. You could, of course, send that file over the network (via email, tcp/ip, carrier pigeon, whatever), and it's even easier if you use built-in erlang distribution primitives, which indeed do this under the hood. Keep in mind that by default values are immutable, so when you're building that lambda it takes out a fixed-in-time reference to that 5 (or whatever, you could even make it user input). In other languages, if that variable changes... Something strange might happen, depending on what that underlying datatype is. In particular, side effects can exist for lists but not scalars in python. In elixir, you can rebind that variable 5 to something else but it won't change the lambda (erlang doesn't allow you to do that at all, except in the repl, sort of). You could also do that with, say, a list datatype, and you get the same deal. for example: list = [1,2,3] lambda = fn -> length(list) end lambda.() #==> 3 list = list ++ [4, 5] list #==> [1,2,3,4,5] lambda.() #==> 3 which is what lets you have a lambda with no expectation on the mutability of the bound-in values. What you get is what you expect, no matter how far away or disconnected or even dead the source is. And that respect for the physics of causality and relativity, at the core, is what makes the BEAM languages so great for distributed systems.
- stouset 7y agoHow is this done securely such that an adversary in your network can’t do the same?
- dnautics 7y agono open ports with arbitrary access, required authentication for the builtin distributed primitives: https://erlang.org/doc/apps/ssl/ssl_distribution.html#specifying-ssl-tls-options https://erlang.org/doc/apps/ssl/ssl_distribution.html#specif...