Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integration with raise4s library #130

Open
rcardin opened this issue Apr 29, 2024 · 0 comments
Open

Integration with raise4s library #130

rcardin opened this issue Apr 29, 2024 · 0 comments

Comments

@rcardin
Copy link

rcardin commented Apr 29, 2024

As I discussed with Adam on X, I opened this issue because I tried integrating my library raise4s with Ox. First, I tried to create a custom ErrorMode:

class RaiseErrorMode[E] extends ErrorMode[E, [T] =>> Raise[E] ?=> T] {

  private val evaluations: scala.collection.mutable.Map[Raise[E] ?=> Any, Either[E, Any]] =
    scala.collection.mutable.Map.empty

  override def isError[T](f: Raise[E] ?=> T): Boolean = {
    if (!evaluations.contains(f)) {
      val result: Either[E, T] = Raise.either(f)
      evaluations.put(f, result)
    }
    evaluations(f).isLeft
  }

  override def getError[T](f: Raise[E] ?=> T): E =
    evaluations(f) match
      case Left(error) => error
      case Right(_)    => throw new IllegalStateException("The raise execution is not an error")

  override def getT[T](f: Raise[E] ?=> T): T =
    evaluations(f) match
      case Right(value) => value.asInstanceOf[T]
      case Left(_)      => throw new IllegalStateException("The raise execution is an error")

  override def pure[T](t: T): Raise[E] ?=> T = t.succeed

  override def pureError[T](e: E): Raise[E] ?=> T = e.raise[T]
}

It works well with the par DSL. However, it doesn't respect the semantics of the race DSL.

val result: String raises Int =
    race(
      {
        sleep(200.millis)
        println("Lambda 1")
        "42"
      }, {
        sleep(100.millis)
        println("Lambda 2")
        Raise.raise(-1)
      }
    )

Raise.fold(
  block = result,
  recover = error => println(s"Error: $error"),
  transform = v => println(s"Transform $v")
)

The above code randomly executes the two lambdas. It does not take into consideration the real execution of the body of the lambda. The issue is in the actual implementation of the race method:

def race[E, F[_], T](em: ErrorMode[E, F])(fs: Seq[() => F[T]]): F[T] =
  unsupervised {
    val result = new ArrayBlockingQueue[Try[F[T]]](fs.size)
    fs.foreach(f => forkUnsupervised(result.put(Try(f()))))
// Omissis

The application f() in the case of a lambda defined in the context Raise[E] ?=> A is the Raise[E] ?=> A lambda itself and not the result of its execution.

So, to integrate the library raise4s with ox, I need to define a custom raceRaise method that uses the Either type:

def raceRaise[E, T](f1: T raises E, f2: T raises E): T raises E =
  raceR(EitherMode[E])(List(() => Raise.either(f1), () => Raise.either(f2))).bind()

Feel free to let me know if you need any more information.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant