Skip to content
Oeiuwq Faith Blog OpenSource Porfolio

funfix/continuations4s

Delimited continuations, for Scala 3, supported across JVM, JS and Native.

funfix/continuations4s.json
{
"createdAt": "2026-02-24T07:09:11Z",
"defaultBranch": "main",
"description": "Delimited continuations, for Scala 3, supported across JVM, JS and Native.",
"fullName": "funfix/continuations4s",
"homepage": "https://continuations4s.funfix.org",
"language": "Shell",
"name": "continuations4s",
"pushedAt": "2026-02-26T06:47:49Z",
"stargazersCount": 19,
"topics": [
"concurrency",
"jvm",
"scala",
"scala-native",
"scalajs"
],
"updatedAt": "2026-03-12T05:33:43Z",
"url": "https://github.com/funfix/continuations4s"
}

Low-level, platform-specific, delimited continuations, implemented for Scala 3, with support for JVM, ScalaJS, and Scala Native. Needed to support cross-platform, “direct style” libraries.

Implementation notes:

  • Scala Native has baked-in delimited continuations support;
  • ScalaJS, using the WASM backend, can use WASM JSPI;
  • On the JVM the implementation blocks threads, which is cheaper to do since Java 21’s virtual threads.

Extracted from the lampepfl/gears project.

libraryDependencies += "org.funfix" %%% "continuations4s" % "0.1.0"

Example — this works across JVM, ScalaJS (WASM) and Scala Native (executable Scala CLI snippet):

//> using scala "3.8.1"
//> using dep "org.funfix::continuations4s::0.1.0"
import continuations4s.Continuations
import scala.concurrent.*
import scala.concurrent.duration.*
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.Try
type Async = Continuations.Label[Unit]
/** For semantically blocking on the result of a `Future`. */
def await[T]!(future: Future[T])(using Async): T = {
val result: Try[T] =
Continuations.suspend[Try[T], Unit] { sus =>
future.onComplete { value =>
sus.resume(value)
}
}
result.get
}
/** End-of-the world execution, to use for ScalaJS in `main`. */
def runToFuture[T]!(body: Async ?=> T): Future[T] = {
val p = Promise[T]!()
val _ = Continuations.boundary[Unit] {
p.complete(Try(body))
}
p.future
}
/** End-of-the world execution, to use in `main` for JVM/Native. */
def runBlocking[T]!(body: Async ?=> T): T = {
import java.util.concurrent.CountDownLatch
var result: Option[Try[T]] = None
val latch = new CountDownLatch(1)
// The result of this `boundary` call can be synchronous, but it's
// not guaranteed (platform-specific), hence the synchronization
// needed via `CountDownLatch` here. Thankfully, the type-system
// forces us to have `Unit` as its result, otherwise we
// couldn't initiate async tasks. Obviously, `runBlocking`
// cannot be implemented on top of ScalaJS (but there we can
// work with Future/Promise at the end-of-the-world).
Continuations.boundary[Unit] {
result = Some(Try(body))
latch.countDown()
}
latch.await()
result.get.get
}
@main def run() = runBlocking {
val f1 = Future(1 + 1) // executed async
val r1 = await(f1) // semantic blocking
val f2 = Future(20 * 2) // executed async
val r2 = await(f2) // semantic blocking
val sum = r1 + r2
println(s"Answer: $sum")
}

You can run it plainly, via the JVM:

Terminal window
scala --enable-markdown \
https://raw.githubusercontent.com/funfix/continuations4s/refs/heads/main/README.md

And you can also execute that via Scala Native to see it in action:

Terminal window
scala \
--native \
--native-version 0.5.10 \
--enable-markdown \
https://raw.githubusercontent.com/funfix/continuations4s/refs/heads/main/README.md

See API documentation.

Copyright 2024-2026 LAMP, EPFL. Copyright 2026 Alexandru Nedelcu.

Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.