Fibers: cooperative coroutines
Ruby-style cooperative coroutines (fiber_new/fiber_resume/fiber_yield/fiber_alive), implemented on real OS threads under the hood but never actually running concurrently: a mutex+condvar pair (ir/fiber.rs) ensures only one fiber's thread is ever unparked at a time, so control passes back and forth explicitly, deterministic and effectively single-threaded โ distinct from parallel_map above, which IS real parallelism. This demo is a classic fiber use case: a lazy, infinite Fibonacci generator the caller pulls values from one at a time, plus a second, independent fiber running the same generator function to show each fiber keeps its own state.
PatLang source
# Fibers: Ruby-style cooperative coroutines, implemented on real OS threads
# under the hood (see ir/fiber.rs) but never actually running concurrently
# -- a mutex+condvar pair ensures only one fiber's thread is ever unparked
# at a time, so control passes back and forth explicitly via fiber_yield/
# fiber_resume, deterministic and single-threaded in effect. Distinct from
# parallel_map (threading_demo.patlang), which IS real parallelism.
#
# Interpreter-only for now: compiled-native fiber support (patc1.exe) is a
# natural follow-up, not yet built -- this demo's transcript is captured
# via `pat --ir-run`, not a compiled binary.
#
# Classic fiber use case: a lazy, infinite generator the caller pulls
# values from one at a time, without the generator needing to know how
# many values will ever be requested.
make a function called fib_generator takes unused returns done
let a = 0
let b = 1
while true do
fiber_yield(a)
let next_val = a + b
let a = b
let b = next_val
end
return "unreachable"
end
let gen = fiber_new("fib_generator")
let i = 0
while i < 12 do
print(fiber_resume(gen, 0))
let i = i + 1
end
print("generator still alive: " + fiber_alive(gen))
# A second, independent fiber running the SAME generator function,
# interleaved with the first -- proof each fiber has its own state
# (a, b) even though both call the same PatLang function.
print("--- a second, independent generator, interleaved ---")
let gen2 = fiber_new("fib_generator")
let j = 0
while j < 5 do
print("gen1: " + fiber_resume(gen, 0) + " gen2: " + fiber_resume(gen2, 0))
let j = j + 1
end
Interpreted run on the build machine (pat --ir-run โ compiled-native fiber support is a natural follow-up, not yet built):
0 1 1 2 3 5 8 13 21 34 55 89 generator still alive: true --- a second, independent generator, interleaved --- gen1: 144 gen2: 0 gen1: 233 gen2: 1 gen1: 377 gen2: 1 gen1: 610 gen2: 2 gen1: 987 gen2: 3
No real "run in browser" button, for the same reason as the threading demo above: fiber_new spawns a real OS thread, unsupported in this WASM sandbox. The step-through below is a purely illustrative, non-functional mock โ the sequence shown is the real transcript's own numbers, stepped through one at a time by a plain JS button, not a live fiber.
Simulated step-through (not live โ see note above):