9 ms·
My favorite Erlang program (2013)
- kitd 7y agoExcuse my Erlang ignorance. When he sends the "{become, F}" message, and F is a function pointer or closure, how is that dispatched across a network? Do the code definitions need to be present remotely too? If so, I'm not sure that quite qualifies as a "universal" server, only a server for locally defined functions. Still cool though. BTW, I've used a similar technique to create a pool of worker goroutines in Golang. Had good performance from it too.
- yetihehe 7y agoThat function's code is serialized and sent to remote node along with necessary data. In erlang, if you want, you can compile whole modules from source constructed at runtime and they behave just like normal code. Typical usage is hot-loading new modules from disk or from other nodes, you load your patch on one node and distribute it over network and if you don't make something stupid, your code is updated in whole system without dropping any tcp connections or the like. Everything happens automatically and every process using old code is updated as soon as possible to new version when possible.
- manthideaal 7y agoif you call a function in the form module:function-name then erlang detect and use the latest compiled version of the module, if you use function-name without the module then the old version is used. Is advised to use the module:function-name in tail call position.
- toast0 7y agoSure, but if you send fun Module:function-name/arity over the network, that will be sent as EXPORT_EXT [1], and only work if the module is available on the receiver. [1] http://erlang.org/doc/apps/erts/erl_ext_dist.html#export_ext http://erlang.org/doc/apps/erts/erl_ext_dist.html#export_ext
- 3fe9a03ccd14ca5 7y agoIn that scenario how do you deploy new code with this method? If you use a new module you must first preinstall it?
- yetihehe 7y agoIf you need to install module on other node, you make a fun which installs that module (typically one function call) and execute it on other node, that fun is automatically sent and executed where you want it. It's like using remote shell (ssh), but your program is automatically sent to remote server.
- toast0 7y agoI wouldn't use function sending to deploy new code in a productionish environment. It's fun to play with, but it's easier to understand a production environment if you push the code/compiled beam files as traditional files through whatever means you like (rsync/packages/whatever), and then load the updated beam files. You could do the code loading by sending a function to the node that calls code:load(Module) and the like; code:soft_purge(Module) first is a good idea to make sure you don't kill lingering processes by accident. You could go all in and have (most of) your Erlang nodes be diskless Erlang, requesting the code to run from another Erlang server when they start, and that seems like a fun adventure, but I don't know if it adds a lot of business value. I'd be happy to play with that on your dime, contact in profile ;)
- dnautics 7y agoHonestly, in most scenarios, you kill the vm and let it restart with new code (just like you would in a kubernetes pod, and in fact using kubernetes pods with BEAM languages is also a valid strategy). If you must keep some state preserved, there's even ways to do it without erlang's hot code reloading strategies, I would recommend watching Dan Azuma's fantastic video (stick around for the live demo): https://www.youtube.com/watch?v=nLApFANtkHs https://www.youtube.com/watch?v=nLApFANtkHs
- jerf 7y agoIf you've ever looked at Erlang's data model briefly and gone "what the heck is with the immutability and lack of user-defined structures, etc.", have another look at it from this point of view of distribution. It's the secret decoder ring of "why did Erlang do it that way?" With another ~25 years of collective experience, if somebody took a shot at it today I think we could make some improvements, but it was pretty far ahead of its time, and can still pull some stunts almost nothing else can, or at least not without creating "an ad-hoc, informally-specified, bug-ridden, slow implementation of half of [Erlang]", to tweak Greenspun a bit.
- afiori 7y agoThere was a nice programming language (unison) posted here some weeks ago that was based on pushing this to the extreme https://news.ycombinator.com/item?id=9512955 https://news.ycombinator.com/item?id=9512955 What I understood was that objects/function are referred by hash of the source/dependency tree so that updates can be propagated transparently.
- deleted 7y ago[deleted]
- manthideaal 7y agoIn 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 ago
- avinassh 7y ago> BTW, I've used a similar technique to create a pool of worker goroutines in Golang. Had good performance from it too. Do you mind telling more about this? Or link, if it’s on Github
- bananadonkey 7y agoNot the OP, but I have used https://github.com/dradtke/distchan https://github.com/dradtke/distchan in prod where portability outweighed the distribution capabilities of Erlang.
- kitd 7y agoSorry, it's not public, but it was based on this: http://marcio.io/2015/07/handling-1-million-requests-per-minute-with-golang/ http://marcio.io/2015/07/handling-1-million-requests-per-min... but made more generic. The 'task' passed to each worker was a closure that was executed by the worker.
- dnautics 7y agoIn erlang you can serialize anything. I can write a lambda and email it to you and you can put it in your VM and assuming you have the correct dependencies, it will probably work. Dependencies are also just atom (universal, global, enum) references, so there's no pointers involved.
- Jtsummers 7y agoHere are a couple previous discussions (only linking ones with comments): https://news.ycombinator.com/item?id=12396420 https://news.ycombinator.com/item?id=12396420 (38 comments) https://news.ycombinator.com/item?id=8807660 https://news.ycombinator.com/item?id=8807660 (2 comments)
- manthideaal 7y agoYou can find more information about erlang in this Ph.D Thesis (1), on page 86 is an example of a universal server, explained with detail. https://erlang.org/download/armstrong_thesis_2003.pdf https://erlang.org/download/armstrong_thesis_2003.pdf
- staticassertion 7y agoThe thesis is, in general, excellent and well worth a read if you're interested in software reliability even outside of Erlang. The first few chapters are just a great read for any developer I think.
- quotha 7y agoMy favorite erlang-based blockchain https://aeternity.com/ https://aeternity.com/
- ProfHewitt 7y agoUnfortunately, Erlang does not directly implement Actor behavior change. Consequently, Erlang cannot directly implement Actor behavior change. A factorial server is implemented below: FactorialServer[ ] *implements* ProcedureServer<[NaturalNumber], NaturalNumber> [i] |-> // received message [i] Factorial.[i] // return result of sending [i] to Factorial In order to implement Actor behavior change, Erlang must resort to using helper processes that trampoline back so that helper processes can return the desired change. See the following for direct implementation of Actor behavior change: https://papers.ssrn.com/abstract=3418003 PS. The type ProcedureServer above can be defined as follows: ProcedureServer<t1, t2> ≡ // Procedure server with parameters types t1 and t2 is defined to be t1 -> t2 // type of procedure from t1 into t2
- gmfawcett 7y agoBy "Actor" I see that you're referring to a particular theory named "Actor", you're not using the term in a colloquial sense. You seem to be saying that Erlang can implement "Actor behaviour change", just not directly. In what sense is this a concern? i.e., what value does direct implementation add here?
- ProfHewitt 7y agoYes, Actor is used in the technical sense axiomatized up to a unique isomorphism in the linked article and not in the common usage of a thespian ;-) Erlang not being able to directly express Actor behavior change means that Erlang programs are more obscure and convoluted. For example, consider the following program: ProcessorController[pk:PublicKey] *implements* controller // initialize processor controller with a public key pk currrentVersion ≔ 1 // processor current version number is initially 1 running ← Crowd [1] // running is a crowd of at most 1 running activities boot[*itemIs* i *whichIs* Package[*imageIS* code, *versionIs* packageVersion], signedIs s] ↦ // received boot request with item i and signed s *IsEmpty* running *cases* // Check if the processor is running True ⇾ // If not running, then SigningChecker.[*itemIs* i, *signedIs* s, *publicKeyIs* pk] *cases* // check that i was signed by s with private key for pk True ⇾ // If signing check succeeds, then currentVersion⩽packageVersion *cases* // check processor current version is // less or equal than package version True ⇾ // If version check succeeds, then (currentVersion ≔ packageVersion; // first update current version number, code.run thru running) // afterward run code in a hole of mutual exclusion passing // thru running then returning a termination report False ⇾ // If version check fails, *Throw* BadVersionException[] // throw bad version exception False ⇾ *Throw* BadSignatureException[] // If signature check fails, False ⇾ // If already running, then *Throw* AlreadyRunningException[] // throw already running exception shutDown ↦ // received shut down request *IsEmpty* running *cases* // Check if the processor is running True ⇾ // If not running, then *Throw* NotRunningException[] //throw not running exception False ⇾ // If already running, then *Cancel* running // cancel running returning Void The challenge in Erlang is to implement the hole in the region of mutual exclusion in the above implementation.
- deleted 7y ago[deleted]
- holtalanm 7y agoRIP Joe Armstrong.
- ProfHewitt 7y agoJoe was a fantastic colleague with whom I had great conversations, e.g., see the following: https://www.youtube.com/watch?v=uORIxJhOjkI https://www.youtube.com/watch?v=uORIxJhOjkI I miss him dearly.
- sergiotapia 7y agoIt's incredible how someone with so much knowledge and programming experience still came down to help newbies in the Elixir forum. He was one of the big reasons why I started learning Elixir and owe the career pivot to him. God bless you Mr. Armstrong.
- holtalanm 7y agoi wish i could write Elixir more on a daily basis. my area is pretty heavily entrenched in the Java / .NET world.
- deleted 7y ago[deleted]