Boundary / break design questions

I’m looking at the implementation of boundary / break, and I almost get it. There are however two points that baffle me.

First, Label: could anyone explain why it’s been made contravariant? I’ve gone through the obvious step of removing the variance annotation to make it fail, but that didn’t seem to phase the compiler.

Second, this bit of code:

  • why use eq rather than == here? I thought in this context they would be exactly equivalent?
  • why keep track of the Label in which break was called? I cannot think of a scenario where it won’t be the closest boundary: block, which is always what we want, isn’t it?

Label is a type of capability. It’s basically offering you a function (return value) => (the return happens). Because its purpose is to specify the type of argument that the return function takes–you have to supply the function as boundary.break–it is in contravariant position.

If eq can be safely used, it could possibly be faster than == which may have to figure out at runtime what kind of equality to call. So, why not?

And jumping multiple levels is a key feature of boundary! For instance, suppose you have a function from which you want to return early, and you want to run a loop inside that you terminate at some point, and sometimes you shortcut your calculation:

function foo(arg: Int): Int =
  boundary[Int]:
    var x = bar(arg)
    boundary: quit ?=>
      while true do
        boundary: skip ?=>
          x = baz(x)
          if finished(x) then boundary.break(x)  // Leaves function (outermost label)
          if done(x) then boundary.break(using quit)
          if enough(x) then boundary.break(using skip)
          x += 1
    x * 2
5 Likes

Perfect, thank you so much.