softwaremill / ox

Safe direct style concurrency and resiliency for Scala on the JVM

Home Page:https://ox.softwaremill.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Proposal: prevent either block nesting to avoid type/try-catch mismatches

lbialy opened this issue · comments

Either blocks, based on boundaries, provide implicit evidence for safe jumps. One problematic case is when .ok() combinator is called on a fork (or inside of exception capturing scope that can swallow a Break), another is when nested boundaries provide evidences for mismatched cases:

val effectMatchingOuterEither: Either[Throwable, Unit] = Left(Exception("oh no"))
val effectMatchingInnerEither: Either[String, Int] = Right(3)

val outer: Either[Throwable, Unit] = either {
  val inner: Either[String, Int] = either {
    effectMatchingOuterEither.ok()
    effectMatchingInnerEither.ok()
  }

  ()
}

Notice that first Either value evaluated with .ok() matches outer either block while being evaluated in the inner block. This might very well be considered a feature - types allow us to decide where to jump - but in my short but stressful experience with this kind of combinators - when this is used with type inference, results can be surprising. In my case the inner block was the body of Tapir handler while outer either block was in main function. The result was, unsurprisingly, a thread killed with Break. I would get a compilation error if nested either blocks were not allowed because without the outer block I'd be informed that it's impossible to use .ok() as either block in tapir handler is inferred to be Either[Unit, String]. I know this is a rather heavy-handed change and there are possible use cases for nested either blocks (tagged jumps for example) but this is confusing enough imho to warrant such a change. I can easily imagine such a change to occur during refactoring of code where inner either block stops matching one of the eithers with .ok() in it's scope and outer either providing evidence where it's no longer handled correctly.

#148

Solved by #148