5 ms·
> There’s a fantastic Elixir project called Rustler. It provides nice support on the Elixir and Rust side for making a safe NIF that is well behaved and using t
by didibus 6y ago
> There’s a fantastic Elixir project called Rustler. It provides nice support on the Elixir and Rust side for making a safe NIF that is well behaved and using the guarantees of Rust is guaranteed not to crash the VM or leak memory
Hum, can someone talk more about these NIF and what special thing Rustler brings?
What's different from just any kind of native interop, like say Java JNI ?
- bluejekyll 6y agoI can’t speak to the Rustler, but the JNI bindings for Rust are quite good. There are a lot of areas where you can still shoot yourself in the foot, lots of unsafe. But there are patterns they encourage that are very safe, like associating lifetimes to Java objects that are instantiated in the Rust code appropriately. It also has good interfaces for working with arrays and avoid some of the foot guns in traditional C JNI libraries. It’s not quite possible to have no unsafe code in JNI with Rust (in my experience) but it is very easy to isolate to very small areas of your code.
- aloukissas 6y agoThe little that I know about NIFs is that if they crash, they bring down the entire BEAM, so it's pretty risky if not done properly. But I've seen that Rust complements Elixir (via NIFs) very well.
- vvanders 6y agoMy brief understanding of NIFs is they're similar to unsafe in Rust where a bunch of VM guarantees are only held so long as the NIF is well-behaved. I believe there was also some limits on how long a NIF could execute before starving the Erlang scheduler[1]. [1] http://erlang.org/doc/man/erl_nif.html http://erlang.org/doc/man/erl_nif.html
- latch 6y agoNIFs run without most (all?) of the safety features the erlang VM provides, such as memory safety and scheduling. If the NIF crashes, the entire app (aka, VM) crashes. This is anathema to some...i dunno..philosophies? expectations? of Erlang/Elixir. NIFs written in Rust (via Rustler) should never be able to crash the VM. Unlike NIFs written in C. Rustler brings other quality of life improvements, like easier interop (decoding/encoding values to and from) and managing the cleanup of objects that live in Rust but are referenced by Elixir.
- pjmlp 6y agoSo what happens to the VM when an index out of bounds happens in Rustler? Is there a panic handler that prevents a crash and returns a magic value that makes sense to the caller?
- filmor 6y agoThe called code is made unwind-safe at the FFI boundary using `std::panic::catch_unwind`. A panic will be converted to an Erlang exception.
- pjmlp 6y agoExcept it doesn't work always, > Note that this function may not catch all panics in Rust. A panic in Rust is not always implemented via unwinding, but can be implemented by aborting the process as well. This function only catches unwinding panics, not those that abort the process.
- c-cube 6y agoIf you compile a NIF you probably will not go out of your way to write "panic = abort" in your project. Unwinding is the default behavior.
- pjmlp 6y agoIt depends on the dependencies.
- bluejekyll 6y agoFrom the docs filmor linked to, if a library sets panic = unwind and a user sets that to abort, “If any of your users choose to abort, they'll get a compile-time failure.”
- pjmlp 6y ago
- lawik 6y agoSo there are a few ways to do interop with non-BEAM languages. Ports are the typical one for simpler things. You start an external command and talk to it via stdin/stdout. NIFs are potentially much faster and are traditionally in C. But they carry the risk of crashing the VM. Rustler+Rust removes most, likely not all, but most of the risks for screwing up and killing the VM. So NIFs are usually not recommended simply because the resilience and reliability of the BEAM VM relies on a bunch of cool strategies inside the VM and NIFs side-step all of that. The Rust ones should be far less dangerous.
- toast0 6y agoI'm not sure if the other answers were good enough. NIF is native interop. There's a bunch of provided functions for interfacing with Erlang terms and other things like that. But, it's native interop, so you can also do whatever crazy stuff you want, even if it's a bad idea. The BEAM VM cannot and does not protect you from bad NIFs; but if you follow the guidelines and are careful not to crash, you can have a good time. Often, the scope of the native work ends up so small, it's easyish to keep it safe. For larger scope, it's more common to use a Port or a C-node; a Port is just what Erlang calls running your other code in separate OS process communicating with stdin/stdout, and a C-node is your other code running separately, possibly on another machine, connected via network sockets, acting like a dist node. For this application though, it makes more sense to use a NIF to avoid copying the data to and from a separate OS process. I haven't used Rustler, but my understanding is it's mostly just a framework of sorts for writing NIFs in Rust. Maybe making it easier to use Erlang terms, and setting up the compile settings etc.
- rkangel 6y agoThe other answers have covered the technical details well, but not so much the philosophical ones. You may have heard about how Erlang with the BEAM is a fantastic implementation of the Actor programming model. This involves lots of processes (green threads) holding a little bit of state and communicating with messages. It's both a great concurrency model and a great programming model. The standard library (OTP) then also provides excellent tools for managing these processes in supervision trees. Ports act like another actor in a supervision tree. This actor happens to be a C program and the messages are sent and received by stdout/stdin, but otherwise it behaves like a process. You can manage its runtime state with supervision trees and all the other excellent tools that BEAM/OTP give you. NIFs on the other hand are best used to replace something that could be a pure function in Erlang, but is a lot faster in something compiled (or because you want to leverage some existing codebase that does that).