Wip sip23 √


@mariusaeriksen, I'm just starting to understand your use case. I now realise that your use case was the probably original motivation for `prepare`. I talked to Phillip Haller and Heather Miller about the origins of `prepare` but I don't think we considered the "capture locals on every async call" use case.

> Another way to go about this may be to disentangle propagation/prepare from ECs and instead define a single, well-known ThreadLocal whose value is always suspended/restored, then hang everything off of that, but I don't think that we can get away from the responsibility of implementations to save context in one form or another.

I think a single well-known ThreadLocal is a great idea. Stick a mutable data structure in there and we avoid needing to call `prepare` everywhere. We'd still need to install and remove the ThreadLocal in the EC's `execute` method, but that behaviour is invisible to any code that uses the EC.

Here's a rough sketch:

```scala
object ExecutionLocals {
  private val threadLocal = new ThreadLocal[mutable.Map[String,Any]]
  def get(name: String): Any = threadLocal.get.apply(name)
  def update(name: String, value: Any): Unit = threadLocal.get.update(name, value)
}

class ExecutionContextWithLocals(map: mutable.Map[String,Any]) extends ExecutionContext {
  import ExecutionLocals._
  def execute(r: Runnable) = {
    ...
    val prev = threadLocal.get
    threadLocal.set(map)
    try r.run() finally threadLocal.set(prev)
    ...
  }
}

// User code

implicit val ec = ExecutionContextWithLocals(mutable.Map.empty)
for {
  x <- Future { ExecutionLocals("a") = 2 }
  y <- ...
  z <- ExecutionLocals.get("a")
} yield ...

```