8 NIFs

This is an example of how to solve the example problem
by using NIFs. NIFs where introduced in R13B03 as an experimental
feature. It is a simpler and more efficient way of calling C-code
than using port drivers. NIFs are most suitable for synchronous functions like
foo and bar in the example, that does some
relatively short calculations without side effects and return the result.

A NIF (Native Implemented Function) is a function that is
implemented in C instead of Erlang. NIFs appear as any other functions to
the callers. They belong to a module and are called like any other Erlang
functions. The NIFs of a module are compiled and linked into a dynamic
loadable shared library (SO in Unix, DLL in Windows). The NIF library must
be loaded in runtime by the Erlang code of the module.

Since a NIF library is dynamically linked into the emulator
process, this is the fastest way of calling C-code from Erlang (alongside
port drivers). Calling NIFs requires no context switches. But it is also
the least safe, because a crash in a NIF will bring the emulator down
too.

Even if all functions of a module will be NIFs, you still need an Erlang
module for two reasons. First, the NIF library must be explicitly loaded
by Erlang code in the same module. Second, all NIFs of a module must have
an Erlang implementation as well. Normally these are minimal stub
implementations that throw an exception. But it can also be used as
fallback implementations for functions that do not have native
implemenations on some architectures.

NIF libraries are loaded by calling erlang:load_nif/2, with the
name of the shared library as argument. The second argument can be any
term that will be passed on to the library and used for
initialization.

We use the directive on_load to get function init to be
automatically called when the module is loaded. If init
returns anything other than ok, such when the loading of
the NIF library fails in this example, the module will be
unloaded and calls to functions within it will fail.

Loading the NIF library will override the stub implementations
and cause calls to foo and bar to be dispatched to
the NIF implementations instead.

The NIFs of the module are compiled and linked into a
shared library. Each NIF is implemented as a normal C function. The macro
ERL_NIF_INIT together with an array of structures defines the names,
arity and function pointers of all the NIFs in the module. The header
file erl_nif.h must be included. Since the library is a shared
module, not a program, no main function should be present.

The function arguments passed to a NIF appears in an array argv,
with argc as the length of the array and thus the arity of the
function. The Nth argument of the function can be accessed as
argv[N-1]. NIFs also takes an environment argument that
serves as an opaque handle that is needed to be passed on to
most API functions. The environment contains information about
the calling Erlang process.

The first argument to ERL_NIF_INIT must be the name of the
Erlang module as a C-identifier. It will be stringified by the
macro. The second argument is the array of ErlNifFunc
structures containing name, arity and function pointer of
each NIF. The other arguments are pointers to callback functions
that can be used to initialize the library. We do not use them
is this simple example so we set them all to NULL.

Function arguments and return values are represented as values
of type ERL_NIF_TERM. We use functions like enif_get_int
and enif_make_int to convert between Erlang term and C-type.
If the function argument argv[0] is not an integer then
enif_get_int will return false, in which case we return
by throwing a badarg-exception with enif_make_badarg.