Nitpick Concurrency & Threading Specification
Nitpick’s concurrency model is divided into two distinct paradigms: Asynchronous Execution (cooperative, I/O-bound multitasking) and System Threading / Atomics (preemptive, CPU-bound parallelism). The language provides native keywords and syntactic sugar for the former, while the latter is enforced via strict, safe standard library abstractions and lock-free primitives.
1. Asynchronous
Execution (async / await)
Nitpick has native syntax for cooperative multitasking via an integrated async runtime.
1.1 Declaring Async Functions
You declare an asynchronous function by prefixing the
definition with the async keyword. Like all
standard Nitpick functions, async functions implicitly
return a Result<T>.
async func:fetch_data = string(string:url) {
// Perform I/O
pass "Data payload";
};
1.2 Awaiting and Unwrapping
To suspend execution until the operation completes, use
await. Crucially, because async functions still
return a Result<T>, you must handle or
unwrap the Result just like a synchronous function. The
raw keyword is placed before
await to safely assert success:
async func:main = int32() {
string:payload = raw await fetch_data("https://example.com");
exit 0i32;
};
1.3 await
Constraints
The await keyword is only valid
inside an async func:. If you attempt
to use await in a standard synchronous
function, the compiler will emit [NITPICK-040],
instructing you to either convert the caller to
async, or spawn the task via the runtime
executor using drop work();.
2. System Threading & Synchronization
Unlike async/await, Nitpick
does not have language-level keywords for
spawning OS threads (e.g., spawn or
go). Instead, threading (thread pools, mutexes,
condition variables, rwlocks, barriers) is handled entirely
by the standard library (stdlib/concurrent)
interfacing with nitpick-libc.
2.1 The sync
Keyword Myth
There is no sync keyword in Nitpick. The
compiler strictly rejects it. Developers must use explicit
atomic types or OS-level mutex abstractions for
synchronization patterns.
3. Lock-Free Atomics
(atomic<T>)
Nitpick provides native lock-free atomic types for
extremely high-performance, non-blocking synchronization
across cores. atomic<T> is a generic
type, not a keyword.
3.1 Initializing Atomics
You must initialize atomics using the
atomic_new builtin rather than standard
assignment.
atomic<int32>:counter = atomic_new(0i32);
3.2 High-Level Atomic Methods
The compiler natively enforces a restricted set of safe
methods on atomic<T> instances: *
.load() * .store(val) *
.swap(val) * .fetch_add(val) *
.fetch_sub(val) *
.compare_exchange(expected, desired)
int32:prev = counter.fetch_add(1i32);
3.3 Strict Sequential Consistency (SeqCst)
To prevent subtle, catastrophic hardware divergence
(especially critical for Nitpick’s AGI and physics engine
goals), the atomic<T> high-level methods
strictly enforce Sequential Consistency
(SeqCst) memory ordering.
Attempting to use method suffixes for weaker orderings
(e.g., counter.load_acquire()) will be rejected
by the compiler. While Nitpick reserves keywords for weaker
orderings (relaxed, acquire,
release, acq_rel,
seq_cst), they are relegated to low-level
compiler intrinsics (e.g., __atomic_load_4)
meant solely for core framework developers, not standard
application code.