Otter - an Erlang-first Rust NIF library (pre-release, feedback wanted)

UPDATE: otter has been released on crates.io as otter-nif! Scroll to the most recent post for details.

I’ve been working on otter, a Rust library for writing Erlang NIFs. It’s at https://github.com/cubelio/otter and I’d like some feedback before cutting a real release.

The motivation: rustler is excellent but it does a lot of magic under the covers that imposes some opinionated decisions that favor Elixir and Mix; there’s no first-class Erlang story. Otter is built for Erlang from the ground up. The design principle is to be as close to using the native NIF API as possible; “if an Erlang programmer wouldn’t recognise a concept, it doesn’t belong.” So no Elixir struct or exception mapping, no NifUntaggedEnum, no Error enum, no inventory/linker magic. Lists are cons cells. NIF registration is explicit. A full comparison is in docs/RUSTLER.md; a side-by-side rustler-to-otter migration guide is in docs/MIGRATION.md.

Three components:

  • otter - core Rust library: all 12 Erlang term types, two-level term resolution (RawTermTerm → data), Env<'a> lifetime safety, resource types with panic-safe callbacks, OwnedEnv for cross-thread sends, select / select_x, time, system info

  • otter_codegen - proc macros for #[otter::nif] and otter::init!

  • rebar3_otter - a rebar3 plugin that drives cargo build (no Mix needed)

Status is 0.1, pre-release. Everything is implemented and exercised end-to-end by an in-tree demo (test_apps/otter_demo), which runs as a rebar3 eunit smoke test covering 26 NIFs across all the term types. The library has not yet been used in production. Requires OTP 26+ (NIF version 2.17), Rust edition 2024, Unix only.

What I’d particularly like feedback on:

  • API shape: does writing a NIF with it feel like working with Erlang?

  • The Erlang-first philosophy: anything missing that you’d expect, or anything included that doesn’t belong?

  • The safety model: Env<'a> is invariant-lifetime so terms can’t escape; panics are caught at the FFI boundary including in resource destructors and down callbacks

  • Anything from rustler you actively miss

GitHub issues or replies here both work.

Thanks,
Lynn

12 Likes

Hi @ldgabbay great timing. We have a few NIFs on Rustler and we’re going to migrate two of them to otter and report back. The Erlang-first philosophy and rebar3_otter plugin are exactly what we’ve been missing. Thanks for sharing this before the release!

1 Like

No problem, I’m really glad it can help! I haven’t landed on a final footprint for the API yet, so be forewarned it might change in the next few weeks depending on feedback. But on the flip side, if there’s anything wrong or you need changed, just ask.

I am currently the active maintainer of rustler. I also wrote rebar_cargo and use it in my production Erlang application. How exactly you build your .so is completely irrelevant. rustler_mix is simply a way to build a library with cargo and place it in the right directory. In Elixir, this is handled via a macro, but you can also simply write your shim module on your own. I have done some work to generate these ad hoc from the build artifact. It would be much nicer if it could be generated directly from the Rust library build, though.

Defaulting to the “latest” NIF version was done in Rustler in the past as well and is quite brittle without any gain if the respective newer APIs aren’t even used.

Also, the Env in NIFs is not “hidden”, it’s simply optional.

And, last comment: Hereby a Rustler maintainer states explicitly that Erlang is intended to be fully supported.

1 Like

No offense intended, I assure you. I’ve updated the docs to make the corrections you wanted and to better communicate the comparison between the two projects. Please let me know if there’s anything else you’d like me to correct or clarify.

1 Like

Thanks for clarifying. I think the docs could make this a bit more explicit :slight_smile: I wasn’t sure myself when I wrote a binding using Rustler.

Well I do hope you give my library a chance when it’s ready.

1 Like

A post was split to a new topic: Otter - write safe, efficient NIFs easily in Rust