10 ms·
For anyone mystified about what a NIF is that doesn't want to go read the docs. The BEAM VM (which is the thing that runs erlang / elixir / gleam / etc) has 3
by ihumanable 2y ago
For anyone mystified about what a NIF is that doesn't want to go read the docs.
The BEAM VM (which is the thing that runs erlang / elixir / gleam / etc) has 3 flavors of functions.
- BIFs - Built-in functions, these are written in C and ship with the VM
- NIFs - Natively implemented functions, these are written in any language that can speak the NIF ABI that BEAM exposes and allows you to provide a function that looks like a built-in function but that you build yourself.
- User - User functions are written in the language that's running on BEAM, so if you write a function in erlang or elixir, that's a user function.
NIFs allow you to drop down into a lower level language and extend the VM. Originally most NIFs were written in C, but now a lot more languages have built out nice facilities for writing NIFs. Rust has Rustler and Zig now has Zigler, although people have been writing zig nifs for a while without zigler and I'm sure people wrote rust nifs without rustler.
- hinkley 2y agoIt’s important to note that while Erlang has protections against user code crashing an Erlang process and recovering, a faulty NIF can take down the entire virtual machine.
- alberth 2y agoHence why Rustler is of so much interest since it provides more protections against this happening. Discord is a big Erlang + Rustler user.
- drawnwren 2y agoIs any of this code open source? As an outsider, I'm kind of at a loss for why anyone wants this or what you kids are doing over there and how offended I should be by it.
- jhgg 2y agohttps://github.com/discord/sorted_set_nif https://github.com/discord/sorted_set_nif
- drawnwren 2y agoAwesome! Thank you! My sarcasm got downvoted heavily (poe's law), but I was genuinely interested.
- alberth 2y agoDo you mean Rustler? Yes, it's Apache 2.0 https://github.com/rusterlium/rustler https://github.com/rusterlium/rustler
- sodapopcan 2y agoTL;DR: Erlang/Elixir/etc are high level languages and the virtual machine they run on, the BEAM, is optimized for speedy IO but is not so great when it comes to intensive CPU tasks. You'll want to write the latter in a good systems language which is what libraries like this provide (you get C bindings out of the box, I believe).
- depr 2y agoAre they really? Their projects don't look so active
- sodapopcan 2y agoIt’s pretty common in the Elixir ecosystem for these types of libraries to not change very much. Elixir itself doesn’t change too much so these libraries stay solid without needing frequent updates. It doesn’t mean people aren’t using them. Some libraries even put disclaimers that they are actively maintained even if they haven’t seen an update in a long time. It’s something that takes some getting used to for some people (including myself at one point).
- andy_ppp 2y agoYeah I was trying to explain this to another developer that packages end up being “finished” eventually and seem to continue to work exceptionally well without updates for a really long time. Something about immutability and the structure of Elixir leads to surprisingly few bugs.
- sbuttgereit 2y agoYep. This is one reason I choose Elixir for a project. For a variety of use cases, long term stability is a big plus.
- photonthug 2y ago> It’s pretty common in the Elixir ecosystem for these types of libraries to not change very much. This is kind of fascinating and seems worthy of more detailed study. I'm sure almost anything looks stable compared to javascript/python ecosystems, but would be interesting to see how other ecosystems with venerable old web-frameworks or solid old compression libraries compare. But on further reflection.. language metrics like "popularity" are also in danger of just quantifying the churn that it takes to keep working stuff working. You can't even measure strictly new projects and hope that helps, because new projects may be a reaction to perceived need to replace other stuff that's annoyingly unstable over periods of 5-10 years, etc. Some churn is introduced by trying to keep up with a changing language, standard lib, or other dependencies, but some is just adding features forever or endlessly refactoring aesthetics under different management. Makes me wish for a project badge to indicate a commitment like finished-except-for-bugfixes.
- deleted 2y ago[deleted]
- johnisgood 2y agoWhat kind of protections as opposed to Zigler?
- alberth 2y agoRust comes with memory safety. It's one less potential cause that might bring down the entire Erlang VM.
- hinkley 2y agoSIGSEGV is a pretty common failure mode alright.
- el_oni 2y agoRustler catches panics before they crash the VM and raises them on the elixir side as an exception. So your process might crash but the vm wont
- kristoff_it 2y agoThat's a neat way to get corrupted state in your application, especially when users of said language don't realize that their language has exceptions. I wrote this recently about Go, but it equally applies to any Rust application that tries to recover from a panic. https://kristoff.it/blog/go-exceptions-unconvinced/ https://kristoff.it/blog/go-exceptions-unconvinced/
- ellroy 2y agoI don't think this is right. The process will crash, and the Supervision strategy you are using will determine what happens from there. This is what the BEAM is all about. The thing with NIFs is that they can crash the entire VM if they error.
- MarcusE1W 2y agoErlang's (Elixirs) error management approach is actually "Let it crash" This is based on the acknowledgment that if you have a large number of longer running processes at some point something will crash anyway, so you may quite as well be good at managing crashes ;-) https://dev.to/adolfont/the-let-it-crash-error-handling-strategy-of-erlang-by-joe-armstrong-25hf https://dev.to/adolfont/the-let-it-crash-error-handling-stra...
- kristoff_it 2y agoThere's a series of things that a NIF must do to be a good citizen. Not crashing is a big one, but also not starving the VM by never yielding (in case the NIF is long-running) is important, plus a few secondary things like using the BEAM allocator so that tooling that monitors memory consumption can see resources consumed by the NIF. The creator of Zigler has a talk from ElixirConf 2021 on how he made Zig NIFs behave nicely: https://www.youtube.com/watch?v=lDfjdGva3NE https://www.youtube.com/watch?v=lDfjdGva3NE
- jlkjfuwnjalfw 2y agoDon't be like me and do a 20ms page fault in a NIF
- bmitc 2y agoIt's also important to point out ports, because as you mention, NIFs are a way to integrate external code. But as someone else points out, NIFs can crash the entire BEAM VM. Ports are a safer way to integrate external code because they are just another BEAM process that talks to an external program. If that program crashes, then the port process crashes just like any other BEAM process but it won't crash the entire BEAM VM.
- gioazzi 2y agoAnd then there are port drivers which are the worst of both worlds! Can crash the BEAM and need much more ceremony than NIF to set up but they’re pretty nice to do in Zig[1] as well [1]: https://github.com/borgoat/er_zig_driver https://github.com/borgoat/er_zig_driver
- bmitc 2y agoThat's true. Haha! There's another option and that's setting up an Erlang node in the other language. The Erlang term format is relatively straightforward. But I'm honestly not sure of the benefit of a node versus just using a port.
- throwawaymaths 2y agoNode: - can "easily" send beam terms back and forth - if you want it to be os-supervised separately (systemd, kubernetes, e.g.) - pain in the ass Port: - easy - usually the only choice if you're not the software author - really only communicates via stdio bytestreams - risk of zombies if... Iirc the stdout is not closed properly? - kind of crazy how it works, Erlang VM spawns a separate process as a middleman
- jerf 2y agoThe Erlang term format is straightforward, but if you want to set up another node in another language you need to correctly implement/emulate process linking, binaries, and some other stuff too, it's not just a matter of writing a socket to accept and emit Erlang terms. It's not impossibly large but it's not something one does on a lark either; if there isn't support in your language already it's hard to justify this over any of the many, many message busses supported by both Erlang and other languages that don't have so many requirements.
- cooljacob204 2y agoDo nifs have the equal process time stuff that regular elixir processes have? Where the BEAM will move the scheduler into another process if it's taking too long? Forgive me if I'm mixing up my terminology it's been a bit since I have poked at Elixir.
- rubyn00bie 2y agoNope, at least not by default or like one would expect from pure Erlang (when it comes to preempting). Been a while since I dug into this admittedly but I write Elixir daily for work (and have for about ten years now). They don’t do the record keeping necessary for the BEAM to interrupt. You need to make sure the “dirty scheduler” is enabled or you can end up blocking other processes on the same scheduler. Here’s a link I found talking about using the dirty scheduler with Rust(ler): https://bgmarx.com/2018/08/15/using-dirty-schedulers-with-rustler/ https://bgmarx.com/2018/08/15/using-dirty-schedulers-with-ru...
- throwawaymaths 2y agoYou can write nifs that way but it seems like a pain in the ass https://www.erlang.org/doc/apps/erts/erl_nif#enif_schedule_nif https://www.erlang.org/doc/apps/erts/erl_nif#enif_schedule_n... After all, many of the BIFs have been replaced internally by NIFs And there's this, which would scare me: https://erlang.org/documentation/doc-15.0-rc3/erts-15.0/doc/html/automaticyieldingofccode.html#introduction https://erlang.org/documentation/doc-15.0-rc3/erts-15.0/doc/...
- b3orn 2y agoBEAM can't preempt native code, that's why NIFs should either be fast/low-latency to not excessively block the scheduler or be put in what's called a dirty scheduler which just means to run it in a separate thread.
- tommica 2y agoUnfortunately Haskell will never be able to have their version of "Zigler"...