[HN Gopher] Enigma: Erlang VM Implementation in Rust ___________________________________________________________________ Enigma: Erlang VM Implementation in Rust Author : adamnemecek Score : 273 points Date : 2020-04-30 14:48 UTC (8 hours ago) (HTM) web link (github.com) (TXT) w3m dump (github.com) | chx wrote: | > sans the distributed bits for now | | I thought the very point of Erlang was the distributed nature of | BEAM? Failure is normal etc? | mwcampbell wrote: | A similar project is Lumen [1], which is targeted primarily at | WebAssembly. | | [1]: https://github.com/lumen/lumen | archseer wrote: | Yep! They appeared shortly after I started and were backed by | Dockyard. I think they didn't have much success finding | external contributors either though :/ | bcardarella wrote: | The project is still under heavy development to get to a | point where external contributors make sense. We hope to be | there soon! | amelius wrote: | What are some good books on the topic of VM implementation? If no | books, then papers also welcome. | | (Not necessarily related to Erlang) | enitihas wrote: | Crafting Interpreters is a good book, free to read online. For | papers you can read "The implementation of Lua 5" | JimmyRuska wrote: | I would love an erlang implementation where there can be many | versions of the code in memory, where you could re-order the | message pattern matching at runtime, where you can specify | arguments to functions in terms of a map, specify the args and | the types of that map specification, and have it compile into | numbered argument, that way you don't have to add update many | many functions to add another argument. | toast0 wrote: | > many versions of the code in memory, | | You can model that today if you script compilation/loading. | When loading a module, you could first load it as {?MODULE, | ?VERSION} or ?MODULE_?VERSION if we can't stuff a tuple there, | and then also load it as ?MODULE, to use when you don't specify | a version. | | The hard part is deciding what version to call when, and | passing that through to the call sites. And also, to figure out | how to signal a process that you want it to update its version. | | > where you could re-order the message pattern matching at | runtime, | | Pattern matching order is part of your code, and hot loading is | the way to make changes to your code. | | > where you can specify arguments to functions in terms of a | map, specify the args and the types of that map specification, | and have it compile into numbered argument, that way you don't | have to add update many many functions to add another argument | | You could do this yourself today as well; a function could | check if its argument is a Map and demapify the arguments, or | you could make a utility call_function(Module, Function, Arity, | Map) that demapifies and calls erlang:apply on the function. | Or, you could have your rapidly changing functions all just | take Maps; I did that in the past with Proplists. | JimmyRuska wrote: | Thanks for these suggestions! | | Shouldn't there be a way for the compiler to know enough to | convert the map to positional arguments, so long as the map | params could be put into a spec? Something like that would be | super nice, because I think tail calls in Erlang cost nothing | so long as you keep the same arg positions. Having a map is | always a convenient way of starting a function and evolving | it, but having it with a few more constraints and with equal | performance would be better. If I'm not mistaken I remember | dart made a similar optimization. | yetihehe wrote: | You could do that already. You can compile code at runtime from | binary (self modifying code) if you need or you could extract | that into several dynamically compiled modules and call them | based on argument. | | BUT | | Different versions of code in memory - that sounds like | nightmare to debug. Erlang already stores two versions of newly | compile code, old one for processes currently actively using | that code and new one for all others. Once all processes jump | to new code (by exiting from old function module or calling | into new version with module:function call) old code is purged. | archseer wrote: | Thanks for sharing, author here! (AMA?) | | I had a lot of fun working on this project, having implemented | enough of the VM to run both Elixir and IEx before I stopped. | | Ultimately development stalled since I couldn't get any community | interest (I was hoping to give an ElixirConf talk but wasn't | accepted either). Was hoping to raise some interest and find some | contributors in similar vein to | https://github.com/RustPython/RustPython | | Nowadays I write a lot less Elixir and a lot more Rust. | jacquesm wrote: | Why start if you have no intention to see it through? Talks and | adoption by the community are a chicken and egg problem, if you | don't believe enough in the project to give it staying power | then the community is right to not adopt it: they already have | a VM for BEAM and it works well. Without an additional selling | point 'now in Rust' doesn't cut it. | GolDDranks wrote: | I find this attitude puzzling. If they wanted to start, why | not? It seems, according to the comment by the author itself, | that they had a lot of fun, and it seemed like an interesting | project. So I don't see any reason to back away from it? On | the other hand, for the precisely same reason, I see | perfectly reasonable that they didn't continue with it. If | the fun is gone, why continue? | merlinsbrain wrote: | > Why start if you have no intention to see it through | | The author had a threshold of good feedback they needed from | the community in a certain amount of time. They got the | feedback they needed - people aren't interested in it, | probably because of the latter part of your comment. | | I don't think that's a valid reason to ask why someone | started a thing, people start things for a variety of | reasons. As far as I am concerned, they saw the development | of a reimplementation of solid tech through and learned a lot | from it. | | > they already have a VM for BEAM and it works well. Without | an additional selling point 'now in Rust' doesn't cut it. | | This is spot on though. | busterarm wrote: | I see this tendency a lot from the Rust community where | there's a lot of "now in Rust" being built, expectations had | and then hurt feelings when they're either ignored or shown | the door. The community seems to think that "now in Rust" | _is_ the selling point. Tools are just tools. | | What they don't realize is that they're often building | solutions that are looking for problems, rather than | solutions to solve problems. It's also vaguely cultish in the | approach. | | It's a terrific language and there's a lot of learn from it, | but I'd like to see it solve real world problems on its own | versus try and screw itself into everyone else's. | 59nadir wrote: | While it's undeniable the majority of things to come out of | Rust are mostly superfluous rewrites of already solid | projects (to your point about "now in Rust!" being the | selling point) I think it's clear the author in this | particular case was just looking into BEAM internals and | started a fun project, so I don't think it applies here. | | In general, though, I think people ought to consider that | if they are putting the language they wrote their project | in in the marketing blurb for it (given a more serious | project), maybe that indicates that the project itself is | of little value to other people. "* Written in Rust" isn't | a value proposition, it's just an implementation detail. | Make real claims about zero crashes, zero leaks, something | actually concrete and it can be scrutinized for real. | chc wrote: | I think you're possibly making a faulty assumption here. | You're right that "written in Rust" has no particular | value to people who just want to use the thing, but | that's not the only perspective people bring to open- | source software. When somebody markets a project as "X | written in Y," I generally assume they're marketing to | people who might want to hack on it, and it _is_ relevant | from that perspective. | merlinsbrain wrote: | Written in X can definitely be a value proposition. | | If you are evaluating a tool/lib/etc that moves at a fast | pace and your whole shop is extremely fluent in language | X there's huge value add to being able to dive in without | a context switch to understand how it works, especially | when debugging harder problems. | | I don't think it applies to _this_ case where we're | getting a VM that is _extremely_ battle-tested. Am I | going to use a new OS instead of linux in production | because someone tried to write an OS in zig? No. Will I | congratulate the author for writing an OS in zig? Yes. | | If I am looking for a key-value store and two are | equivalent in their purported features and stability, I | will choose the one that is written in X that my shop is | most fluent in. | tomp wrote: | How did you implement the GC? Is it possible to implement an | allocator + GC in Rust without hitting UB? | enitihas wrote: | You can simply use unsafe as an escape hatch | adamnemecek wrote: | Do you think it's reasonable to make a Rust library that allows | you to do Erlang style binary matching? | | That's what I was originally looking for when I found this. | swsieber wrote: | If your okay with macros, probably nightly only, then it | seems reasonable. | | There is also slice matching on stable, which let's you match | on parts of slices: https://github.com/rust- | lang/rust/pull/67712/ . It went out in 1.42. It has some | stuff which makes binary stuff easier, but not by much. But | perhaps someday you'll get native binary matching in the | language that's closer to what Erlang offers. | | It made it in the 1.42 release. | hopia wrote: | A new Erlang VM with just replicated functionality is a fairly | hard sell to the Erlang/Elixir community, who brag with the | industrial track record of the BEAM. | | I believe you'd get much more interest if there was some | ambitious new promise for this new VM, such as 10x sequential | performance etc. | themgt wrote: | If the VM is in Rust could it be compiled to WASM? | rkangel wrote: | You wouldn't want to, for various reasons. See this blog | post about Lumen and the decision decisions: | | https://tylerscript.dev/bringing-the-beam-to-webassembly- | wit... | hobofan wrote: | You wouldn't want to _right now_. However for almost all | points there is a solution underway/in planning. In a | year or two it might be feasible. | | There would however be other limitations, like filesystem | APIs etc. not being available in the browser that a lot | of frameworks in BEAM languages expect, that would | severely limit the usefulness, though I guess that | applies to either implementation strategy. | dnautics wrote: | I think the point though is that architecturally there | are performance hits if you don't respect the fact that | WASM has a different architecture than what the BEAM | expects (harvard vs von neumann IIRC), so you may NEVER | want to if you get it right in the first place. | wahern wrote: | The Harvard-Von Neumann dichotomy is wrong. C also works | perfectly fine on Harvard architectures--it's why | function pointers in C are special, aren't guaranteed to | be convertible to a void pointer, and why uintptr_t is | optional. POSIX adds these additional guarantees to | support dlsym, which returns function addresses as void | pointers. | | The problems with compiling other languages to Web | Assembly are primarily 1) lack of goto and 2) inability | to instantiate and jump between different stacks. These | limitations are especially problematic for languages like | Erlang/BEAM and Go because Web Assembly-based VM | implementations require an extra level of indirection in | order to implement some of their core language semantics, | resulting in quite slow performance compared to even a | pure, strictly compliant C implementation (and presuming | the WASM VM itself adds no overheard, which is not | actually the case). | | WASM excluded goto support because it was argued that the | relooper algorithm required to translate goto constructs | to structured WASM statements was sufficiently capable to | cover the vast majority of existing code. And they | provided evidence to back up that claim. The flaw in that | reasoning is that language implementations and similar | niche cases have special needs that application code | rarely requires, and in that space constructs like goto | are crucial to both simplicity of implementation and | performance; the inadequacies of relooper become the norm | rather than the exception. | dnautics wrote: | thanks for the clarification! | jlg23 wrote: | Just being able to amend job requirements with "or rust | experience" is most probably worth it. | dnautics wrote: | Someday this is going to need to happen though. IMO, "the | right way" to do this is via the strangler pattern: | | https://www.michielrook.nl/2016/11/strangler-pattern- | practic... | | Probably the language that is most poised to achieve this is | Zig; it would be feasible to start by wrapping the entire | BEAM in a zig compilation unit; which at the very least | potentially offers an easier path to maintaining the codebase | across multiple platforms. Followed by hodgepodge doing bits | and pieces in zig, which could be achieved via | straightforward transliteration at first. | | The very different mindset of the rust PL lends itself to | total rewrites, which I don't think will sit well in the BEAM | community. On the other hand erlang has tons of strange | rewrites happening over its own internal ecosystem all the | time (gen_fsm -> gen_statem, pg -> pg2 -> pg), etc. | muizelaar wrote: | Do you know of any examples of this being done with Zig? I | can think of a couple with Rust: | | - https://gitlab.gnome.org/GNOME/librsvg completed a | migration to Rust. | | - https://github.com/RazrFalcon/rustybuzz and | https://github.com/immunant/rexpat are making decent | progress. | dnautics wrote: | No, because zig is still in 0.6.0, and the BDFL says | "don't use this in prod yet"? Yeesh. | fortran77 wrote: | We do a lot of Erlang work here. The BEAM is so reliable that | I wouldn't spend 1 minute looking at an experimental | alternative. | carapace wrote: | Yeah, this. I'm just getting started with Erlang and I | already feel like an idiot for not using it sooner. When I | think of some of the things I've done to try to achieve | what the BEAM does out-of-the-box... | rhlsthrm wrote: | Can you give some examples? I've been getting more and | more interested in Erlang. | battery_cowboy wrote: | RPC is basically built in, so you'll probably never use | REST internally. There's an in memory database built in | (ETS) that will replace redis for most key value storage | cases. There's easy recovery from crashes via supervision | trees and associated features. You can do hot upgrades | while your system is fully operational. | spockz wrote: | Can you share something on this reliability? Is it more | reliable than the JVM? Or is it more predictable in terms | of performance? I've found the jvm itself to be rock solid | as well. | hopia wrote: | Erlang VM is consistent/predictable in terms of latency, | it's engineered that way. For pure computational | performance you won't find it optimal. | archseer wrote: | Yeah I definitely didn't see it being production ready any | time soon, but I thought it was an interesting project for | people that wanted to learn BEAM internals. That's how I got | started with it at least, I had problems trying to contribute | BEAM just because of the sheer size of the codebase and | lacking the domain specific knowledge. | | I do think that having alternative implementations is good | for experimentation though, similar to how Ruby was improved | upon ideas from JRuby and Rubinius, even if most users never | used those two directly. | conradfr wrote: | There is some go projects like [1] that can connect to Erlang | nodes and claim to be speedier. | | [1] https://github.com/halturin/ergo | organicfigs wrote: | Nice work! If I wanted to learn how to build VMs, how would I | start? My experience is in backend development/distributed | systems in Java and Go (so assume I know nothing outside of an | introductory OS course) | Aqua_Geek wrote: | The "Crafting Interpreters" book by Bob Nystrom is probably a | good way to dig in. It has a whole chunk on implementing a | VM: http://craftinginterpreters.com/a-bytecode-virtual- | machine.h... | organicfigs wrote: | This is pretty engaging, thank you! | shijie wrote: | Thank you for posting this! Thanks to you I'm digging in to | this book right now and having a blast. The author is an | engaging writer and it's been tremendous fun thus far. | Aqua_Geek wrote: | His book, "Game Programming Patterns," is great as well: | http://gameprogrammingpatterns.com | songshuu wrote: | A VM is more than enough of a project, but are there any | thoughts of a Phoenix port? | ethelward wrote: | Why would you want to port Phoenix? As long as the underlying | VM follow the spec, Phoenix should be oblivious of on which | it is running. | d4mi3n wrote: | I love seeing new implementations of popular languages. | | Curious: Did implementing this in Rust expose any bad or | interesting behavior when replicating the Erlang language spec | (https://github.com/erlang/spec) or whatever reference | implementation you were targeting? | archseer wrote: | If I remember correctly I found a few edge cases, but they | weren't ever hit by OTP, just by partially implemented VMs | like mine :) | | It was kind of interesting exploring the OTP internals, | especially some of the parts that haven't changed in a long | time. One example is the PAM: I think it stood for "patrick's | abstract machine" and it would compile erlang terms into | bytecode for pattern matches (intended for fast ETS lookups). | It's all there in one file and it took a fair bit of digging | to figure out how it works since it's been static for a long | while and nothing on the internet really documented it. | callamdelaney wrote: | The pattern matching algorithm was originally based on the | algorithm described in `The implementation of Functional | Programming Languages`, the 1987 edition (there are two | versions, one is more basic). | | Edit: this book is available for free here: | https://www.microsoft.com/en-us/research/publication/the- | imp... | d4mi3n wrote: | Hah! Great find! | | If this is still the case you should definitely consider | contributing to the documentation of those files. Odds are | they'll be used by the next person to try something | similar. :) | throwaway894345 wrote: | This is cool, but looks like development has stalled. Last commit | was Sept 2019. ___________________________________________________________________ (page generated 2020-04-30 23:00 UTC)