Concurrency
As of version v0.4, Hachi includes first-phase concurrency support for transpiled builds.
The model is intentionally lightweight and Go-inspired, centered around:
go:for spawning work asynchronouslyChannel<T>for typed message passing- direct channel operations such as
makeChannel,send,recv, andclose - non-blocking, timeout-aware, and select-style receive/send helpers
This page covers the currently supported concurrency features and how to use them.
Overview
Hachi concurrency in v0.4 is built around explicit task spawning and typed channels.
A typical flow looks like this:
- create a channel with
makeChannel - start one or more workers with
go: - send values into or out of channels
- receive values from channels
- close channels when finished
Spawning Tasks with go:
Use go: to start a function asynchronously.
ping :: {} -> {Void}:(
print: "hello from a task"
)
go: ping
You can also pass arguments:
worker :: {Int} -> {Void}:(
print: Ri.a.String
)
go: worker: 42
You can pass multiple arguments as well:
producer :: {Channel<Int>, Int} -> {Void}:(
send: Ri.a, Ri.b
)
ch: makeChannel: Int
go: producer: ch, 99
print: recv: ch
close: ch
Supported go: Argument Types
At the current v0.4 stage, go: is intended for practical transpiled concurrency and supports:
VoidIntByteBoolFltStringChannel<T>- tuples composed of those types
Channels
Channels are typed with Channel<T>.
numbers: Channel<Int>
messages: Channel<String>
In most code, you will create them using makeChannel rather than declaring the type alone.
Creating Channels
Create a channel with:
ch: makeChannel: Int
You can also provide an explicit capacity:
ch: makeChannel: Int, 3
Capacity Notes
In the current v0.4 implementation:
makeChannel: Tcreates a channel with capacity1makeChannel: T, Ncreates a channel with capacityN- channel capacity must be at least
1
So while the model is Go-inspired, the default channel behavior is currently a single-slot channel rather than a zero-capacity unbuffered channel.
Sending and Receiving
Send a value into a channel with send:
send: ch, 42
Receive a value with recv:
x: recv: ch
print: x
Basic Example
ch: makeChannel: Int
send: ch, 42
print: recv: ch
close: ch
Worker Example
ch: makeChannel: Int
worker :: {} -> {Void}:(
send: ch, 42
)
go: worker
print: recv: ch
close: ch
Closing Channels
Use close when you are done with a channel:
close: ch
As a general rule:
- close channels when no more values should be sent
- do not send to a channel after closing it
- close channels deliberately rather than implicitly relying on program exit
Buffered Channels
Channels can hold more than one value when created with a larger capacity.
ch: makeChannel: Int, 3
send: ch, 1
send: ch, 2
send: ch, 3
print: recv: ch
print: recv: ch
print: recv: ch
close: ch
This is useful for simple producer/consumer patterns and small pipelines.
Non-Blocking Receive
Use tryRecv when you want to check a channel without blocking.
res: tryRecv: ch
The result includes:
res.okas aBoolres.valueas the received value when available
Example:
ch: makeChannel: Int
send: ch, 42
res: tryRecv: ch
res.ok ? (
print: res.value
) | (
print: "empty"
)
close: ch
Timeout Receive
Use timeoutRecv to wait for a limited amount of time.
res: timeoutRecv: ch, 20
Timeout values are in milliseconds.
The result includes:
res.okres.value
Example:
ch: makeChannel: Int
res: timeoutRecv: ch, 20
res.ok ? (
print: res.value
) | (
print: "timeout"
)
close: ch
Non-Blocking Send
Use trySend when you want to attempt a send without blocking.
ok: trySend: ch, 99
This returns a Bool indicating whether the value was successfully sent.
Example:
ch: makeChannel: Int, 1
a: trySend: ch, 1
b: trySend: ch, 2
print: a
print: b
close: ch
Select-Style Receive
Hachi includes select-style receive helpers for multiple channels of the same inner type.
trySelectRecv
Checks several channels without blocking.
res: trySelectRecv: a, b
The result includes:
res.okres.indexres.value
res.index tells you which channel was selected.
Example:
a: makeChannel: Int
b: makeChannel: Int
send: b, 42
res: trySelectRecv: a, b
print: res.ok
print: res.index
print: res.value
close: a
close: b
selectRecv
Blocks until one of the channels can provide a value.
res: selectRecv: a, b
The result includes:
res.okres.indexres.value
Example:
a: makeChannel: Int
b: makeChannel: Int
producer :: {Channel<Int>} -> {Void}:(
send: Ri.a, 20
)
go: producer: b
res: selectRecv: a, b
print: res.ok
print: res.index
print: res.value
close: a
close: b
timeoutSelectRecv
Waits up to a timeout for one of several channels to provide a value.
res: timeoutSelectRecv: a, b, 200
Timeout values are in milliseconds.
The result includes:
res.okres.indexres.valuewhen available
Example:
a: makeChannel: Int
b: makeChannel: Int
producer :: {Channel<Int>} -> {Void}:(
send: Ri.a, 42
)
go: producer: b
res: timeoutSelectRecv: a, b, 2000
print: res.ok
print: res.index
print: res.value
close: a
close: b
Select-Style Send
Hachi also includes select-style send helpers.
trySelectSend
Attempts to send to one of several channels without blocking.
res: trySelectSend: a, 10, b, 20
The result includes:
res.okres.index
Example:
a: makeChannel: Int, 1
b: makeChannel: Int, 1
res: trySelectSend: a, 10, b, 20
print: res.ok
print: res.index
close: a
close: b
selectSend
Blocks until one of several send operations can succeed.
res: selectSend: a, 10, b, 20
The result includes:
res.okres.index
Example:
a: makeChannel: Int, 1
b: makeChannel: Int, 1
consumer :: {Channel<Int>} -> {Void}:(
x: recv: Ri.a
print: x
)
go: consumer: b
res: selectSend: a, 10, b, 20
print: res.ok
print: res.index
close: a
close: b
timeoutSelectSend
Waits up to a timeout for one of several send operations to succeed.
res: timeoutSelectSend: a, 11, b, 22, 200
Timeout values are in milliseconds.
The result includes:
res.okres.index
Example:
a: makeChannel: Int
b: makeChannel: Int
send: a, 5
res: timeoutSelectSend: a, 11, b, 22, 200
print: res.ok
print: res.index
x: recv: b
print: x
close: a
close: b
A Small Pipeline Example
jobs: makeChannel: Int, 2
results: makeChannel: Int, 2
worker :: {} -> {Void}:(
x: recv: jobs
send: results, x * 2
y: recv: jobs
send: results, y * 2
)
send: jobs, 3
send: jobs, 4
go: worker
print: recv: results
print: recv: results
close: jobs
close: results
Current Notes and Caveats
- The current concurrency support is first-phase and aimed at transpiled/native builds
- Channels are typed and work best when all participating operations agree on the inner type
makeChannel: Tcurrently defaults to capacity1- timeout values are in milliseconds
tryRecvandtimeoutRecvreturn a result object with.okand.value- select-style receive operations return
.ok,.index, and.value - select-style send operations return
.okand.index selectRecvandselectSendare blocking operations- the transpiled runtime waits at exit for outstanding asynchronous work
Recommended Usage Style
For current Hachi code, a good practical style is:
- use
go:for clear worker/task boundaries - prefer channels for message passing instead of shared mutable state
- use
tryRecvandtrySendwhen you want polling behavior - use timeout helpers when you need bounded waits
- use select-style operations when coordinating multiple channels
- close channels intentionally and consistently
As Hachi grows, concurrency support may continue to expand, but the features on this page reflect the current v0.4 behavior.