Native (mobile)
Effects, subscriptions and threads
Because an IO closure can't cross the thread boundary (only JSON-serialised actions can), cross-thread work is expressed as dispatching an action to the thread that should handle it. Two combinators do this:
runOnBG action- run
action'supdateon the background thread (BTS). Used by a main-thread event handler that needs to change shared state, since the BTS solely owns the model. runOnMain action- run
action'supdateon the main thread (MTS). Used by a BTS effect that needs an imperative main-thread operation (seeMiso.Native.MainThread).
Each ships only the given action to the target thread (or dispatches it locally when already there), where its update runs exactly once. Sibling effects in the current update are unaffected, and nothing is double-executed. Off the native runtime both are an ordinary local dispatch, equivalent to issue.
Subscriptions and threads
A Sub is dynamic — it is just a Sink action -> IO () run in a forked thread — and a component's subs are started on every thread it mounts on. So a sub runs on both the BTS and the MTS (once each), and each copy dispatches into its own thread's scheduler.
Because a sub is ordinary runtime IO — unlike a static event handler, whose thread is fixed at compile time — it selects its own thread at runtime with the mts / bts booleans. This is the dynamic analogue of a handler's *Main variant:
-- background-only: open the socket once, feed the model
wsSub sink = when bts (websocketConnect "wss://…" sink)
-- main-thread-only: drive an imperative animation
animSub _ = when mts (eachFrame step)