2026-01-24 23:40:22 +01:00
<!DOCTYPE html>
<!-- retoor <retoor@molodetz.nl> -->
< html lang = "en" >
< head >
< meta charset = "UTF-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
< title > Fibers - Wren-CLI Manual</ title >
< link rel = "stylesheet" href = "../css/style.css" >
</ head >
< body >
< button class = "mobile-menu-toggle" > Menu</ button >
< div class = "container" >
< aside class = "sidebar" >
< div class = "sidebar-header" >
< h1 >< a href = "../index.html" > Wren-CLI</ a ></ h1 >
< div class = "version" > v0.4.0</ div >
</ div >
< nav class = "sidebar-nav" >
< div class = "section" >
< span class = "section-title" > Getting Started</ span >
< ul >
< li >< a href = "../getting-started/index.html" > Overview</ a ></ li >
< li >< a href = "../getting-started/installation.html" > Installation</ a ></ li >
< li >< a href = "../getting-started/first-script.html" > First Script</ a ></ li >
< li >< a href = "../getting-started/repl.html" > Using the REPL</ a ></ li >
</ ul >
</ div >
< div class = "section" >
< span class = "section-title" > Language</ span >
< ul >
< li >< a href = "index.html" > Syntax Overview</ a ></ li >
< li >< a href = "classes.html" > Classes</ a ></ li >
< li >< a href = "methods.html" > Methods</ a ></ li >
< li >< a href = "control-flow.html" > Control Flow</ a ></ li >
< li >< a href = "fibers.html" class = "active" > Fibers</ a ></ li >
< li >< a href = "modules.html" > Modules</ a ></ li >
</ ul >
</ div >
< div class = "section" >
< span class = "section-title" > API Reference</ span >
< ul >
< li >< a href = "../api/index.html" > Overview</ a ></ li >
2026-01-25 04:58:39 +01:00
< li >< a href = "../api/string.html" > String</ a ></ li >
< li >< a href = "../api/number.html" > Num</ a ></ li >
2026-01-24 23:40:22 +01:00
< li >< a href = "../api/http.html" > http</ a ></ li >
< li >< a href = "../api/websocket.html" > websocket</ a ></ li >
< li >< a href = "../api/tls.html" > tls</ a ></ li >
< li >< a href = "../api/net.html" > net</ a ></ li >
< li >< a href = "../api/dns.html" > dns</ a ></ li >
< li >< a href = "../api/json.html" > json</ a ></ li >
< li >< a href = "../api/base64.html" > base64</ a ></ li >
< li >< a href = "../api/regex.html" > regex</ a ></ li >
< li >< a href = "../api/jinja.html" > jinja</ a ></ li >
< li >< a href = "../api/crypto.html" > crypto</ a ></ li >
< li >< a href = "../api/os.html" > os</ a ></ li >
< li >< a href = "../api/env.html" > env</ a ></ li >
< li >< a href = "../api/signal.html" > signal</ a ></ li >
< li >< a href = "../api/subprocess.html" > subprocess</ a ></ li >
< li >< a href = "../api/sqlite.html" > sqlite</ a ></ li >
< li >< a href = "../api/datetime.html" > datetime</ a ></ li >
< li >< a href = "../api/timer.html" > timer</ a ></ li >
< li >< a href = "../api/io.html" > io</ a ></ li >
2026-01-25 04:58:39 +01:00
< li >< a href = "../api/pathlib.html" > pathlib</ a ></ li >
2026-01-24 23:40:22 +01:00
< li >< a href = "../api/scheduler.html" > scheduler</ a ></ li >
< li >< a href = "../api/math.html" > math</ a ></ li >
</ ul >
</ div >
< div class = "section" >
< span class = "section-title" > Tutorials</ span >
< ul >
< li >< a href = "../tutorials/index.html" > Tutorial List</ a ></ li >
< li >< a href = "../tutorials/http-client.html" > HTTP Client</ a ></ li >
< li >< a href = "../tutorials/websocket-chat.html" > WebSocket Chat</ a ></ li >
< li >< a href = "../tutorials/database-app.html" > Database App</ a ></ li >
< li >< a href = "../tutorials/template-rendering.html" > Templates</ a ></ li >
< li >< a href = "../tutorials/cli-tool.html" > CLI Tool</ a ></ li >
</ ul >
</ div >
< div class = "section" >
< span class = "section-title" > How-To Guides</ span >
< ul >
< li >< a href = "../howto/index.html" > How-To List</ a ></ li >
< li >< a href = "../howto/http-requests.html" > HTTP Requests</ a ></ li >
< li >< a href = "../howto/json-parsing.html" > JSON Parsing</ a ></ li >
< li >< a href = "../howto/regex-patterns.html" > Regex Patterns</ a ></ li >
< li >< a href = "../howto/file-operations.html" > File Operations</ a ></ li >
< li >< a href = "../howto/async-operations.html" > Async Operations</ a ></ li >
< li >< a href = "../howto/error-handling.html" > Error Handling</ a ></ li >
</ ul >
</ div >
</ nav >
</ aside >
< main class = "content" >
< nav class = "breadcrumb" >
< a href = "../index.html" > Home</ a >
< span class = "separator" > /</ span >
< a href = "index.html" > Language</ a >
< span class = "separator" > /</ span >
< span > Fibers</ span >
</ nav >
< article >
< h1 > Fibers</ h1 >
< p > Fibers are Wren's mechanism for cooperative concurrency. They are lightweight threads of execution that you explicitly control. Unlike OS threads, only one fiber runs at a time, and switching between them is explicit.</ p >
< h2 > Creating Fibers</ h2 >
< p > Create a fiber with < code > Fiber.new</ code > :</ p >
< pre >< code > var fiber = Fiber.new {
System.print("Inside fiber")
}</ code ></ pre >
< p > The fiber does not run immediately. It is suspended until you start it.</ p >
< h2 > Running Fibers</ h2 >
< h3 > call()</ h3 >
< p > Start a fiber and wait for it to complete or yield:</ p >
< pre >< code > var fiber = Fiber.new {
System.print("Running")
}
fiber.call() // Prints "Running"</ code ></ pre >
< h3 > try()</ h3 >
< p > Start a fiber and catch any runtime errors:</ p >
< pre >< code > var fiber = Fiber.new {
Fiber.abort("Something went wrong")
}
var error = fiber.try()
System.print("Error: %(error)") // Error: Something went wrong</ code ></ pre >
< h2 > Yielding</ h2 >
< p > Fibers can pause execution and return control to the caller:</ p >
< pre >< code > var fiber = Fiber.new {
System.print("First")
Fiber.yield()
System.print("Second")
Fiber.yield()
System.print("Third")
}
fiber.call() // Prints "First"
fiber.call() // Prints "Second"
fiber.call() // Prints "Third"</ code ></ pre >
< h3 > Yielding Values</ h3 >
< pre >< code > var counter = Fiber.new {
Fiber.yield(1)
Fiber.yield(2)
Fiber.yield(3)
}
System.print(counter.call()) // 1
System.print(counter.call()) // 2
System.print(counter.call()) // 3</ code ></ pre >
< h3 > Passing Values In</ h3 >
< pre >< code > var adder = Fiber.new {
var total = 0
while (true) {
var value = Fiber.yield(total)
total = total + value
}
}
adder.call() // Start the fiber
System.print(adder.call(5)) // 5
System.print(adder.call(10)) // 15
System.print(adder.call(3)) // 18</ code ></ pre >
< h2 > Fiber State</ h2 >
< p > Check the state of a fiber:</ p >
< pre >< code > var fiber = Fiber.new {
Fiber.yield()
}
System.print(fiber.isDone) // false
fiber.call()
System.print(fiber.isDone) // false (yielded)
fiber.call()
System.print(fiber.isDone) // true (completed)</ code ></ pre >
< h2 > Error Handling</ h2 >
< p > Fibers can abort with an error:</ p >
< pre >< code > Fiber.abort("Error message")</ code ></ pre >
< p > Use < code > try()</ code > to catch errors:</ p >
< pre >< code > var fiber = Fiber.new {
var x = 1 / 0 // Will cause infinity, not error
[1, 2, 3][10] // This will cause an error
}
var error = fiber.try()
if (error != null) {
System.print("Caught: %(error)")
}</ code ></ pre >
< h2 > Current Fiber</ h2 >
< p > Get the currently executing fiber:</ p >
< pre >< code > var current = Fiber.current
System.print(current) // Fiber instance</ code ></ pre >
< h2 > Generator Pattern</ h2 >
< p > Fibers naturally implement generators:</ p >
< pre >< code > var range = Fn.new { |start, end|
return Fiber.new {
var i = start
while (i < = end) {
Fiber.yield(i)
i = i + 1
}
}
}
var nums = range.call(1, 5)
while (!nums.isDone) {
var value = nums.call()
if (value != null) System.print(value)
}</ code ></ pre >
< h2 > Coroutine Pattern</ h2 >
< p > Two fibers can communicate back and forth:</ p >
< pre >< code > var producer = Fiber.new {
for (i in 1..5) {
System.print("Producing %(i)")
Fiber.yield(i)
}
}
var consumer = Fiber.new {
while (!producer.isDone) {
var value = producer.call()
if (value != null) {
System.print("Consuming %(value)")
}
}
}
consumer.call()</ code ></ pre >
< h2 > Async Operations with Scheduler</ h2 >
< p > Wren-CLI uses fibers for async I/O. The scheduler suspends fibers during I/O and resumes them when the operation completes:</ p >
< pre >< code > import "timer" for Timer
System.print("Before sleep")
Timer.sleep(1000) // Fiber suspends here
System.print("After sleep")</ code ></ pre >
< p > The scheduler pattern internally looks like:</ p >
< pre >< code > import "scheduler" for Scheduler
Scheduler.await_ {
Timer.sleep_(1000, Fiber.current)
}</ code ></ pre >
< h2 > Fiber Methods</ h2 >
< h3 > Static Methods</ h3 >
< table >
< tr >
< th > Method</ th >
< th > Description</ th >
</ tr >
< tr >
< td >< code > Fiber.new { block }</ code ></ td >
< td > Create a new fiber</ td >
</ tr >
< tr >
< td >< code > Fiber.current</ code ></ td >
< td > Get the current fiber</ td >
</ tr >
< tr >
< td >< code > Fiber.yield()</ code ></ td >
< td > Pause and return null</ td >
</ tr >
< tr >
< td >< code > Fiber.yield(value)</ code ></ td >
< td > Pause and return value</ td >
</ tr >
< tr >
< td >< code > Fiber.abort(message)</ code ></ td >
< td > Abort with error</ td >
</ tr >
< tr >
< td >< code > Fiber.suspend()</ code ></ td >
< td > Suspend the current fiber</ td >
</ tr >
</ table >
< h3 > Instance Methods</ h3 >
< table >
< tr >
< th > Method</ th >
< th > Description</ th >
</ tr >
< tr >
< td >< code > fiber.call()</ code ></ td >
< td > Run fiber, wait for yield/complete</ td >
</ tr >
< tr >
< td >< code > fiber.call(value)</ code ></ td >
< td > Run with value passed to yield</ td >
</ tr >
< tr >
< td >< code > fiber.try()</ code ></ td >
< td > Run and catch errors</ td >
</ tr >
< tr >
< td >< code > fiber.isDone</ code ></ td >
< td > True if completed</ td >
</ tr >
< tr >
< td >< code > fiber.error</ code ></ td >
< td > Error message if aborted</ td >
</ tr >
< tr >
< td >< code > fiber.transfer()</ code ></ td >
< td > Switch to this fiber</ td >
</ tr >
< tr >
< td >< code > fiber.transfer(value)</ code ></ td >
< td > Switch with value</ td >
</ tr >
< tr >
< td >< code > fiber.transferError(msg)</ code ></ td >
< td > Switch and raise error</ td >
</ tr >
</ table >
< h2 > Transfer vs Call</ h2 >
< p >< code > call()</ code > maintains a call stack and returns when the fiber yields:</ p >
< pre >< code > var a = Fiber.new {
System.print("a: before yield")
Fiber.yield()
System.print("a: after yield")
}
a.call()
System.print("back in main")
a.call()
// Output:
// a: before yield
// back in main
// a: after yield</ code ></ pre >
< p >< code > transfer()</ code > does not maintain a call stack:</ p >
< pre >< code > var main = Fiber.current
var a = null
var b = null
a = Fiber.new {
System.print("in a")
b.transfer()
System.print("back in a")
main.transfer()
}
b = Fiber.new {
System.print("in b")
a.transfer()
System.print("back in b")
}
a.transfer()
System.print("done")
// Output:
// in a
// in b
// back in a
// done</ code ></ pre >
</ article >
< footer class = "page-footer" >
< a href = "control-flow.html" class = "prev" > Control Flow</ a >
< a href = "modules.html" class = "next" > Modules</ a >
</ footer >
</ main >
</ div >
< script src = "../js/main.js" ></ script >
</ body >
</ html >