Best (Active) delimited continuations for Scala


#1

Greetings, I’m in the process of writing a hobby language, and was thinking of writing it in Scala because of the rather unique set of requirements my language has, what I need is a efficient way of performing delimited multi-shot continuations. Scala with it’s myriad of meta-programming tools seems like a good place to start.

At the core of what I’m looking for is a function to state machine transform like those found in C#, I know async/await exists in Scala, but I need a few more features:

  1. I’d like tight control over the types inside the state machines, there are cases where I need to convert the concrete types inside the state machines. So I’ll code against a interface, but I need to convert the value before assigning it to a field. Part of the work I’m doing here involves Truffle and GraalVM where VirtualFrames can exist only on the stack, and have to be materialized before storing in the heap.

  2. I’d like to only switch into this state machine code when needed. That is, if a given code path doesn’t require suspending execution then the function should return code as-is, in a perfect world this could be done by handing a box to a child function. If the box contains null, then we know a normal value was returned from the function, otherwise the box will contain the continuation.

  3. I’d really like these state machines to be clone-able. I’d like to make this whole thing to mult-shot. So I should be able to get a state machine, clone it, then execute both clones without them clobbering each other (assuming the both aren’t mutating some global state or collection.

This all seems really specific, but I figured there’s some sort of Scala library that would allow me to rewrite annotated functions to do all of this. Any pointers to tools or docs would be great.

Thanks!

Timothy Baldridge


#2

That sounds like a really interesting project!

It’s a bit difficult to suggest a metaprogramming solution for you at the moment as the chief metaprogramming tool that most developers are using at the moment (scala.reflect macros) is going to be deprecated for Scala 3 in favour of a proposed new framework. If you don’t mind the fact that the future of macro annotations is still up in the air there are a few resources about them available and a lot of resources about writing scala.reflect macros around (let us know if you need help finding those):

I’m not really sure about the details of your project but there are also some interesting libraries for tree and graph rewriting which you might find helpful

Along with some great projects for describing and suspending computations

As for the specific features you were looking for:

  1. I think you would typically use a type class to do this in Scala. This would allow you to constrain the interface you are using such that it requires a converter for the type that is used at the call site into the underlying type.
  2. Most of the concurrency libraries in the Scala ecosystem offer some method to efficiently import bare values into the carrier type for your computation so I think you will be able to do this with whatever library you like, perhaps after inspecting the AST in your annotation macro to decide whether that is necessary
  3. The two libraries listed above both allow you to describe your computation as an immutable data structure before running it, so it is cloneable in that sense

Hope that helps!