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.