---
{
"@context": "https://nxdlang.org/schema",
"doc_id": "CB001",
"title": "",
"description": "",
"category": "Cookbook Appendix",
"layer": "Cookbook Appendix",
"keywords": [],
"version": "1.4.5",
"status": "active"
}
```
# CB001 COOKBOOK APPENDIX
## APPENDIX A
### ***A.1 Result module***
### NXD surface
#### MODULE RESULT:
```nxd
TYPE RESULT UNION { OK(any), ERR(string) }
FUNC OK(V):
RETURN OK(V)
FUNC ERR(MSG):
RETURN ERR(MSG)
FUNC IS_OK(R):
MATCH R:
CASE OK(_):
RETURN true
OTHERWISE:
RETURN false
FUNC IS_ERR(R):
MATCH R:
CASE ERR(_):
RETURN true
OTHERWISE:
RETURN false
FUNC UNWRAP_OR(R, DEFAULT):
MATCH R:
CASE OK(V):
RETURN V
CASE ERR(_):
RETURN DEFAULT
FUNC MAP_OK(R, FN):
MATCH R:
CASE OK(V):
RETURN OK(FN(V))
CASE ERR(MSG):
RETURN ERR(MSG)
```
### Nim mapping
#### Idiomatic Nim uses Result[T]:
```nim
type
Result[T] = object
isOk: bool
ok: T
err: string
proc ok[T](v: T): Result[T] =
Result[T](isOk: true, ok: v, err: "")
proc err[T](msg: string): Result[T] =
Result[T](isOk: false, err: msg)
proc isOk[T](r: Result[T]): bool =
r.isOk
proc isErr[T](r: Result[T]): bool =
not r.isOk
proc unwrapOr[T](r: Result[T], default: T): T =
if r.isOk: r.ok else: default
proc mapOk[T, U](r: Result[T], fn: proc(x: T): U): Result[U] =
if r.isOk:
ok(fn(r.ok))
else:
err[U](r.err)
```
### Elixir mapping
#### Use tagged tuples:
```elixir
defmodule Result do
def ok(v), do: {:ok, v}
def err(msg), do: {:error, msg}
def is_ok({:ok, _}), do: true
def is_ok(_), do: false
def is_err({:error, _}), do: true
def is_err(_), do: false
def unwrap_or({:ok, v}, _default), do: v
def unwrap_or({:error, _}, default), do: default
def map_ok({:ok, v}, fn), do: {:ok, fn.(v)}
def map_ok({:error, msg}, _fn), do: {:error, msg}
end
```
### D mapping
#### Use a templated Result:
```d
module result;
struct Result(T) {
bool isOk;
T ok;
string err;
}
Result!T ok(T)(T v) {
return Result!T(true, v, "");
}
Result!T err(T)(string msg) {
Result!T r;
r.isOk = false;
r.err = msg;
return r;
}
bool isOk(T)(Result!T r) {
return r.isOk;
}
bool isErr(T)(Result!T r) {
return !r.isOk;
}
T unwrapOr(T)(Result!T r, T defaultValue) {
return r.isOk ? r.ok : defaultValue;
}
Result!U mapOk(T, U)(Result!T r, U function(T) fn) {
if (r.isOk) {
return ok!U(fn(r.ok));
} else {
return err!U(r.err);
}
}
```
### ***A.2 Concurrent module***
### NXD surface
#### MODULE CONCURRENT
```nxd
TYPE CHANNEL(any)
FUNC MAKE_CHANNEL():
RETURN CHANNEL()
FUNC SPAWN(FN):
SPAWN FN()
FUNC SEND(CH, MSG):
SEND MSG TO CH
FUNC RECV(CH):
LET V SET RECV CH
RETURN V
FUNC TASK(FN):
RETURN SPAWN FN()
FUNC AWAIT(T):
RETURN AWAIT T
```
### Nim mapping
#### Use asyncdispatch or channels:
```nim
import asyncdispatch, channels
type
Channel[T] = Channel[T] # from channels module
proc makeChannel[T](): Channel[T] =
newChannel[T]()
proc spawn*(fn: proc() {.async.}): Future[void] =
asyncCheck fn()
proc send[T](ch: Channel[T], msg: T) =
ch.send(msg)
proc recv[T](ch: Channel[T]): T =
ch.recv()
proc task*(fn: proc() {.async.}): Future[void] =
spawn(fn)
proc await*[T](f: Future[T]): T =
waitFor f
```
### Elixir mapping
#### Processes + message passing:
```elixir
defmodule Concurrent do
def make_channel do
self()
end
def spawn(fn) do
spawn(fn)
end
def send(ch, msg) do
send(ch, msg)
end
def recv(_ch \\ self()) do
receive do
msg -> msg
end
end
def task(fn) do
Task.async(fn)
end
def await(task) do
Task.await(task)
end
end
```
### D mapping
#### Threads + channels (e.g., std.concurrency):
```d
module concurrent;
import std.concurrency;
import core.thread;
alias Channel(T) = Tid; // simplistic: a thread id as channel
Channel!T makeChannel(T)() {
// in practice you'd spawn a worker that receives messages
return thisTid;
}
void send(T)(Channel!T ch, T msg) {
send(ch, msg);
}
T recv(T)() {
auto m = receiveOnly!T();
return m;
}
Thread spawn(void function() fn) {
auto t = new Thread(fn);
t.start();
return t;
}
// task/await could wrap std.concurrency or futures libs
```
## Appendix B — Dynamic Trait Objects (`BOX<TRAIT>`)
Dynamic trait objects allow NXD to support runtime polymorphism in addition to compile‑time trait constraints.
They behave like interface objects or protocol dispatch in backends.
### B.1 Concept
A dynamic trait object is a runtime value that stores:
• a reference to a concrete value
• a vtable containing implementations of the trait’s functions
This enables:
• heterogeneous collections
• runtime dispatch
• plugin architectures
• dynamic capability wrappers
### B.2 Syntax
#### Trait definition
```nxd
TRAIT SERIALIZABLE {
FUNC TO_STRING(X): string
}
```
#### Type implementing trait
```nxd
TYPE USER IMPLEMENTS SERIALIZABLE:
NAME: string
FUNC TO_STRING(U: USER): string:
RETURN "USER(" ADD U.NAME ADD ")"
```
#### Dynamic trait object creation
```nxd
LET B SET BOX<SERIALIZABLE>(U)
```
#### Dynamic dispatch
```nxd
FUNC LOG_OBJ(X: BOX<SERIALIZABLE>):
PRINTLN(X.TO_STRING())
```
### B.3 Semantics
#### B.3.1 Type erasure
`BOX<SERIALIZABLE>` hides the concrete type.
Only trait methods are accessible.
#### B.3.2 Lifetime
A `BOX<T>` owns the underlying value unless constructed with BORROW.
#### B.3.3 Borrowed trait objects
`LET B SET BOX<SERIALIZABLE>(BORROW U)`
Borrowed trait objects do not own the underlying value.
#### B.3.4 Equality
Trait objects use identity equality, not value equality.
### B.4 Backend mapping
#### Nim
• Lowered to ref object with proc table
• Dynamic dispatch via manually constructed vtables
#### Elixir
• Lowered to protocol dispatch
• Struct stored directly; protocol resolution at runtime
#### D
• Lowered to interface + class or struct wrapper
• Vtable dispatch native
### B.5 Limitations
• Trait objects cannot be serialized unless the trait defines a serialization method.
• Trait objects cannot be sent through channels unless explicitly allowed.
## Appendix C — Ownership Patterns
NXD uses a lightweight ownership model compatible with Nim ARC/ORC, Elixir GC, and D RAII/GC.
### C.1 Owned Values
Owned values are created normally:
```nxd
LET BUF SET MAKE_BUFFER()
```
The creator owns the value.
### C.2 Borrowed Values
Borrowing creates a non-owning reference:
```nxd
USE_BUFFER(BORROW BUF)
```
Rules:
• Borrow is immutable
• Multiple borrows allowed
• Borrow does not extend lifetime beyond owner
### C.3 Move Semantics
Move transfers ownership:
```nxd
LET BUF2 SET MOVE BUF
```
After move:
• BUF becomes invalid
• BUF2 owns the value
### C.4 Ownership Across Processes
Ownership transfer across processes must be explicit:
```nxd
SEND MOVE BUF TO CH
```
Borrowing across processes is allowed but discouraged unless safe.
### Appendix D — Security Patterns
NXD’s security model is capability‑based.
These patterns show how to structure secure code.
### D.1 Capability‑Guarded API
Every sensitive function requires a capability:
```nxd
FUNC READ_SECURE(PATH: string, CAP: CAP_FS_READ): string:
RETURN READ_FILE(PATH)
```
### D.2 Least Privilege Process
Give each process only the capabilities it needs:
```nxd
SPAWN WORKER(CAP_FS_READ)
SPAWN LOGGER(CAP_LOG_WRITE)
```
### D.3 Capability Delegation
Explicit delegation:
```nxd
SEND CAP TO CH
```
Only allowed if capability is delegable.
### D.4 Capability Revocation
```nxd
REVOKE(CAP)
```
Revocation is global for that capability instance.
## Appendix E — Package Design Patterns
These patterns help structure NXD packages for clarity and portability.
### E.1 Core + Backend Adapters
```text
mypkg/
core/
types.nxd
logic.nxd
nim/
runtime_shim.nxd
elixir/
runtime_shim.nxd
d/
runtime_shim.nxd
```
Rules:
• Core contains pure NXD logic
• Backend folders contain runtime shims
• No backend conditionals in core code
### E.2 Facade Pattern
Expose a stable API:
MODULE mypkg.api
IMPORT mypkg.core
IMPORT mypkg.nim
Backend differences hidden behind the facade.
### E.3 Capability‑Scoped Packages
Packages declare required capabilities:
```nxd
[capabilities]
requires = ["FS_READ", "NET_CONNECT"]
```
## Appendix F — Backend Portability Patterns
These patterns ensure code runs consistently across Nim, Elixir, and D.
### F.1 Portability Profile
Each package declares its portability requirements:
```nxd
[portability]
requires = ["RESULT", "OPTION", "CHANNEL"]
```
### F.2 Portable Subset
To maximize portability:
• Avoid UNSAFE
• Avoid backend‑specific concurrency primitives
• Use:• RESULT
• OPTION
• channels
• tasks
• traits
### F.3 Backend Capability Matrix
Feature Nim Elixir D
RESULT native emulated native
OPTION native emulated native
MOVE ARC/ORC hint RAII/hint
BORROW hint N/A hint
CHANNEL native wrapped native
UNSAFE full limited full
TRAITS concepts protocols interfaces/templates
INIT static @on_load static this()
PROCESS threads BEAM processes threads/fibers
TASK futures Task std.concurrency
## Appendix G — Cross‑Backend Examples
This appendix demonstrates how core NXD abstractions lower into Nim, Elixir, and D.
It is not normative; it is illustrative.
### G.1 Futures / Tasks Examples
(NXD TASK / AWAIT → Nim futures, Elixir Task, D std.concurrency)
#### NXD
```nxd
FUNC WORK(X: int): int:
RETURN X MUL 2
FUNC MAIN():
LET T SET TASK(WORK, 21)
LET R SET AWAIT T
MATCH R:
CASE OK(V): PRINTLN(V)
CASE ERR(E): PRINTLN("error: " ADD E)
```
#### Nim
```nim
import asyncdispatch
proc work(x: int): Future[int] {.async.} =
return x * 2
proc main() =
let t = work(21)
let r = waitFor t
echo r
```
#### Elixir
```elixir
def work(x), do: x * 2
def main() do
t = Task.async(fn -> work(21) end)
r = Task.await(t)
IO.puts(r)
end
```
#### D
```d
import std.concurrency;
int work(int x) {
return x * 2;
}
void main() {
auto tid = spawn(&work, 21);
auto r = receiveOnly!int;
writeln(r);
}
```
### G.2 Collections Examples
(LIST, MAP, mutation, iteration)
#### NXD
```nxd
FUNC MAIN():
LET L SET [1,2,3]
L.PUSH(4)
LET M SET { "x": 10, "y": 20 }
M["z"] SET 30
FOR V IN L:
PRINTLN(V)
FOR K,V IN M:
PRINTLN(K ADD ":" ADD V)
```
#### Nim
```nim
var L = @[1,2,3]
L.add(4)
var M = {"x": 10, "y": 20}.toTable
M["z"] = 30
for v in L:
echo v
for k,v in M:
echo k, ":", v
```
#### Elixir
```elixir
def main() do
l = [1,2,3] ++ [4]
m = %{"x" => 10, "y" => 20} |> Map.put("z", 30)
Enum.each(l, &IO.puts/1)
Enum.each(m, fn {k,v} ->
IO.puts("#{k}:#{v}")
end)
end
```
#### D
```d
import std.stdio;
import std.array;
import std.algorithm;
void main() {
auto L = [1,2,3];
L ~= 4;
int[string] M;
M["x"] = 10;
M["y"] = 20;
M["z"] = 30;
foreach(v; L)
writeln(v);
foreach(k,v; M)
writeln(k, ":", v);
}
```
### G.3 Type Examples
(Structs, traits, generics, constraints)
#### NXD
```nxd
TRAIT SERIALIZABLE {
FUNC TO_STRING(X): string
}
TYPE POINT IMPLEMENTS SERIALIZABLE:
X: int
Y: int
FUNC TO_STRING(P: POINT): string:
RETURN "(" ADD P.X ADD "," ADD P.Y ADD ")"
FUNC PRINT<T : SERIALIZABLE>(X: T):
PRINTLN(TO_STRING(X))
```
#### Nim
```nim
type
Point = object
x, y: int
proc toString(p: Point): string =
"(" & $p.x & "," & $p.y & ")"
proc print[T](x: T) =
echo toString(x)
```
#### Elixir
```elixir
defprotocol Serializable do
def to_string(x)
end
defmodule Point do
defstruct [:x, :y]
end
defimpl Serializable, for: Point do
def to_string(%Point{x: x, y: y}), do: "(#{x},#{y})"
end
def print(x), do: IO.puts(Serializable.to_string(x))
```
#### D
```d
interface Serializable {
string toString();
}
struct Point {
int x;
int y;
string toString() {
return "(" ~ x.to!string ~ "," ~ y.to!string ~ ")";
}
}
void print(T)(T x) if (is(T : Serializable)) {
writeln(x.toString());
}
```
### G.4 Capability Examples
(Creation, delegation, revocation, use)
#### NXD
```nxd
FUNC READ_SECURE(PATH: string, CAP: CAP_FS_READ): string:
RETURN READ_FILE(PATH)
FUNC MAIN():
LET CAP SET FS_READ_CAP()
LET T SET TASK(READ_SECURE, "data.txt", CAP)
LET R SET AWAIT T
MATCH R:
CASE OK(V): PRINTLN(V)
CASE ERR(E): PRINTLN("error: " ADD E)
REVOKE(CAP)
```
#### Nim
(Capabilities lowered to explicit parameters + runtime checks)
```nim
type FsReadCap = object
proc readSecure(path: string, cap: FsReadCap): string =
readFile(path)
proc main() =
let cap = FsReadCap()
let t = async(readSecure("data.txt", cap))
let r = waitFor t
echo r
```
#### Elixir
(Capabilities lowered to explicit arguments + pattern checks)
```elixir
def read_secure(path, :fs_read_cap) do
File.read!(path)
end
def main() do
cap = :fs_read_cap
t = Task.async(fn -> read_secure("data.txt", cap) end)
r = Task.await(t)
IO.puts(r)
end
```
#### D
(Capabilities lowered to structs + runtime validation)
```d
struct FsReadCap {}
string readSecure(string path, FsReadCap cap) {
return import(path);
}
void main() {
auto cap = FsReadCap();
auto tid = spawn(&readSecure, "data.txt", cap);
auto r = receiveOnly!string;
writeln(r);
}
```
## Appendix G.5 — Channel lifecycle examples
(Creation, send/recv, closing, draining, errors)
#### NXD
```nxd
FUNC MAIN():
LET CH SET MAKE_CHANNEL<int>(CAPACITY 2)
# producer
SPAWN:
SEND 1 TO CH
SEND 2 TO CH
SEND 3 TO CH # error: channel full
CLOSE CH
# consumer
LET A SET RECV CH # 1
LET B SET RECV CH # 2
LET C SET RECV CH # error: channel closed and empty
```
#### Nim
```nim
import asyncdispatch, channels
proc producer(ch: Channel[int]) {.async.} =
ch.send(1)
ch.send(2)
# third send may block or error depending on impl
ch.close()
proc consumer(ch: Channel[int]) {.async.} =
try:
let a = await ch.recv()
let b = await ch.recv()
let c = await ch.recv() # error after close+empty
except ChannelClosedError:
echo "channel closed"
proc main() =
let ch = newChannel[int](2)
asyncCheck producer(ch)
asyncCheck consumer(ch)
runForever()
```
#### Elixir
```elixir
defmodule Chan do
use GenServer
def start_link(cap \\ 2), do: GenServer.start_link(__MODULE__, {[], cap})
def send(pid, v), do: GenServer.call(pid, {:send, v})
def recv(pid), do: GenServer.call(pid, :recv)
def close(pid), do: GenServer.cast(pid, :close)
def init({buf, cap}), do: {:ok, %{buf: buf, cap: cap, closed: false}}
def handle_call({:send, v}, _from, %{closed: true} = s),
do: {:reply, {:error, :closed}, s}
def handle_call({:send, v}, _from, %{buf: buf, cap: cap} = s) when length(buf) < cap,
do: {:reply, :ok, %{s | buf: buf ++ [v]}}
def handle_call({:send, _}, _from, s),
do: {:reply, {:error, :full}, s}
def handle_call(:recv, _from, %{buf: [h | t]} = s),
do: {:reply, {:ok, h}, %{s | buf: t}}
def handle_call(:recv, _from, %{buf: [], closed: true} = s),
do: {:reply, {:error, :closed}, s}
def handle_call(:recv, _from, s),
do: {:reply, {:error, :empty}, s}
def handle_cast(:close, s), do: {:noreply, %{s | closed: true}}
end
def main() do
{:ok, ch} = Chan.start_link(2)
Task.start(fn ->
Chan.send(ch, 1)
Chan.send(ch, 2)
Chan.send(ch, 3) # {:error, :full}
Chan.close(ch)
end)
IO.inspect Chan.recv(ch) # {:ok, 1}
IO.inspect Chan.recv(ch) # {:ok, 2}
IO.inspect Chan.recv(ch) # {:error, :closed}
end
```
#### D
```d
import std.stdio;
import std.concurrency;
import std.container;
struct Channel(T) {
Array!T buf;
size_t cap;
bool closed;
this(size_t c) { cap = c; }
void send(T v) {
if (closed) throw new Exception("channel closed");
if (buf.length >= cap) throw new Exception("channel full");
buf.insertBack(v);
}
T recv() {
if (buf.length > 0) {
auto v = buf.front;
buf.removeFront();
return v;
}
if (closed) throw new Exception("channel closed");
throw new Exception("channel empty");
}
void close() { closed = true; }
}
void producer(Tid consumer, Channel!int ch) {
ch.send(1);
ch.send(2);
try ch.send(3); catch (Exception e) writeln(e.msg);
ch.close();
consumer.send(ch);
}
void consumer() {
auto ch = receiveOnly!(Channel!int);
writeln(ch.recv()); // 1
writeln(ch.recv()); // 2
try writeln(ch.recv()); catch (Exception e) writeln(e.msg);
}
void main() {
auto c = spawn(&consumer);
auto ch = Channel!int(2);
auto p = spawn(&producer, c, ch);
}
```
## Appendix G.6 — Trait object examples
(Static traits now, dynamic trait objects as future pattern)
#### NXD — static trait use (current spec)
```nxd
TRAIT SERIALIZABLE {
FUNC TO_STRING(X): string
}
TYPE USER IMPLEMENTS SERIALIZABLE:
NAME: string
FUNC TO_STRING(U: USER): string:
RETURN "USER(" ADD U.NAME ADD ")"
FUNC LOG<T : SERIALIZABLE>(X: T):
PRINTLN(TO_STRING(X))
FUNC MAIN():
LET U SET USER("gabriel")
LOG(U)
```
#### Nim — static trait‑like pattern
```nim
type
User = object
name: string
proc toString(u: User): string =
"USER(" & u.name & ")"
proc log[T](x: T) =
echo toString(x)
proc main() =
let u = User(name: "gabriel")
log(u)
```
#### Elixir — protocol‑based static dispatch
```elixir
defprotocol Serializable do
def to_string(x)
end
defmodule User do
defstruct [:name]
end
defimpl Serializable, for: User do
def to_string(%User{name: name}), do: "USER(#{name})"
end
def log(x), do: IO.puts(Serializable.to_string(x))
def main() do
u = %User{name: "gabriel"}
log(u)
end
```
#### D — interface‑based trait object (future NXD pattern)
If you later allow `BOX<SERIALIZABLE>` as a dynamic trait object:
```d
TRAIT SERIALIZABLE {
FUNC TO_STRING(X): string
}
TYPE USER IMPLEMENTS SERIALIZABLE:
NAME: string
FUNC TO_STRING(U: USER): string:
RETURN "USER(" ADD U.NAME ADD ")"
FUNC LOG_OBJ(X: BOX<SERIALIZABLE>):
PRINTLN(X.TO_STRING())
FUNC MAIN():
LET U SET USER("gabriel")
LET B SET BOX<SERIALIZABLE>(U)
LOG_OBJ(B)
```
#### D lowering:
```d
interface Serializable {
string toString();
}
class User : Serializable {
string name;
this(string n) { name = n; }
string toString() { return "USER(" ~ name ~ ")"; }
}
void logObj(Serializable x) {
writeln(x.toString());
}
void main() {
auto u = new User("gabriel");
logObj(u);
}
```
## Appendix H - Error Handling Patterns
## Appendix I - Actor/Process Design Patterns
## Appendix J - State Machines
## Appendix K - Memory Safe Patterns
## Appendix L - Compiler Construction Examples
## Appendix M - Capability Security Cookbook
## Appendix N - Backend Differences Cookbook
## Appendix O - Pitfalls
## Appendix P - "Real Programs"
Documentation