Ports, NIFs & C Nodes

{packet, 4} adds a 4-byte length header to each message — the external program must read/write that framing.

Port (external program) full (separate OS process) safe integration with any language Port driver (linked-in C) legacy; prefer NIFs none — a crash kills the VM small, fast native functions full (separate node) C program acting as an Erlang node

35.1 Ports

{packet, 4} adds a 4-byte length header to each message — the external program must read/write that framing. Ports are linked to their owner; the external program sees EOF on stdin when the port closes.

Port = open_port({spawn, "python3 -u upper.py"}, [binary, {packet, 4}, exit_status]),
port_command(Port, term_to_binary(hello)),
receive
    {Port, {data, Data}} -> binary_to_term(Data);
    {Port, {exit_status, S}} -> {exited, S}
end,
port_close(Port).

35.2 NIFs

NIFs should return in < 1 ms; otherwise use dirty schedulers (ERL_NIF_DIRTY_JOB_CPU_BOUND / IO_BOUND), yield with enif_schedule_nif, or use threads.

Resource objects (enif_open_resource_type) wrap C pointers with GC-managed destructors.

Safer languages: Rustler (Rust), Zigler (Zig), nifty.

-module(fast_math).
-export([add/2]).
-nifs([add/2]).
-on_load(init/0).

init() -> erlang:load_nif(filename:join(code:priv_dir(myapp), "fast_math"), 0).
add(_A, _B) -> erlang:nif_error(nif_not_loaded).
#include <erl_nif.h>

static ERL_NIF_TERM add(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
    int a, b;
    if (!enif_get_int(env, argv[0], &a) || !enif_get_int(env, argv[1], &b))
        return enif_make_badarg(env);
    return enif_make_int(env, a + b);
}

static ErlNifFunc nif_funcs[] = { {"add", 2, add, 0} };
ERL_NIF_INIT(fast_math, nif_funcs, NULL, NULL, NULL, NULL)

35.3 C nodes & jinterface

erl_interface/ei library lets C programs speak the distribution protocol; jinterface does the same for Java.