Packages

Mojo NIFs for OTP 28. Generated ABI, checked terms, resources, dirty schedulers, and a Mix compiler. Mojo 1.1.0 is required at build time and is not vendored.

Current section

Files

Jump to
mojoler docs tutorial 02-mojo-essentials.md
Raw

docs/tutorial/02-mojo-essentials.md

# Unit 2 — Mojo language essentials

## Objectives

Read the subset of Mojo 1.1.0 this repo actually compiles: `def`, structs, origins, and the absence of file-scope `alias`.

## Why

A snippet from an older Mojo post uses `fn` or `alias` and never reaches the linker. The NIF bug then looks like an OTP bug.

## Model

```text
def name(...) abi("C") -> c_ulong     callback the VM calls
struct ... (RegisterPassable)         C layout, if the fields match
Pointer[T, MutUntrackedOrigin]        VM or calloc memory
[o: Origin]                           a pointer to a local the callee may use
```

## Theory

`def` replaced `fn` (E4). There is no module-level `var` (E9), which is why `nif_init` calls `calloc`. A file-scope `alias` is a parse error in this compiler, so `abi_major()` is a function that returns `c_int(2)`.

`Pointer` is non-null. Failure is `Optional[Pointer]`. `Optional` of a thin function was 16 bytes and cannot sit in a callback slot. `Optional[Pointer]` is 8 bytes and None is all zeros (E7).

Writing through `Pointer[T, MutUntrackedOrigin]` from Mojo failed when the argument was a local (`origin_of(result)`). The ABI wrappers take `[o: Origin]` so `Pointer(to=local)` typechecks. A Mojo function that needs to *store* through that pointer is a different problem: the user arithmetic returns an `AddResult` struct instead of writing through the pointer.

## Lab

Open `native/mojoler/abi/otp_nif.mojo` and `native/examples/arith_user.mojo`. Confirm there is no line that starts with `alias`.

## Expected

Constants are `def abi_...` functions. `checked_add` returns `AddResult`.

## Code

`native/poc.mojo` is the short version of the same rules: one struct assignment into memory from `alloc_funcs`, one `make_entry`, one exported `nif_init`.

## Failure

`cannot implicitly convert` on a pointer origin means the wrapper's origin parameter was pinned to `MutUntrackedOrigin` or `MutAnyOrigin` and the local does not match. The fix used here is a generic origin, not a cast that throws the check away without a comment.

## Exercise

Why is `enif_get_int64` absent from the generated imports?

## Answer

On this OTP it is a macro for `enif_get_long` because `SIZEOF_LONG` is 8 (E6). The generator records that in a comment and emits `enif_get_long`.