Giter Club home page Giter Club logo

interop-cats's Introduction

ZIO Interop Cats

Installation

libraryDependencies += "dev.zio" %% "zio-interop-cats" % "<latest-version>"

ZIO Cats Effect 3 instances

ZIO integrates with Typelevel libraries by providing an instance of Concurrent, Temporal and Async for Task as required, for instance, by fs2, doobie and http4s.

For convenience, the ZIO library defines an alias as follows:

type Task[A] = ZIO[Any, Throwable, A]

Therefore, we provide Cats Effect instances based on this specific datatype.

Concurrent

In order to get a Concurrent[Task] or Concurrent[RIO[R, *]] (note * is kind-projector notation) we need to import zio.interop.catz._:

import cats.effect._
import zio._
import zio.interop.catz._

def ceConcurrentForTaskExample = {
  val F: cats.effect.Concurrent[Task] = implicitly
  F.racePair(F.unit, F.unit)
}

Temporal

import cats.effect._
import zio._
import zio.interop.catz._

def ceTemporal = {
  val F: cats.effect.Temporal[Task] = implicitly
  F.sleep(1.second) *> F.unit
}

Async

import cats.effect._
import zio._
import zio.interop.catz._

def ceAsync = {
  val F: cats.effect.Async[Task] = implicitly
  F.racePair(F.unit, F.sleep(1.second) *> F.unit)
}

Other typeclasses

There are many other typeclasses and useful conversions that this library provides implementations for:

  • See zio/interop/cats.scala file to see all available typeclass implementations for the Cats Effect 3 typeclasses
  • See zio/stream/interop/cats.scala for ZStream typeclass implementations
  • See zio/stream/interop/FS2StreamSyntax.scala for FS2 <-> ZStream conversions

cats-core

If you only need instances for cats-core typeclasses, not cats-effect import zio.interop.catz.core._:

import zio.interop.catz.core._

Note that this library only has an Optional dependency on cats-effect – if you or your libraries don't depend on it, this library will not add it to the classpath.

Example

The following example shows how to use ZIO with Doobie (a library for JDBC access) and FS2 (a streaming library), which both rely on Cats Effect instances (cats.effect.Async and cats.effect.Temporal):

import zio.{durationInt as _, *}
import zio.interop.catz.*
import doobie.*
import doobie.implicits.*
import scala.concurrent.duration.*

object Example extends ZIOAppDefault:
  val run = {
    val xa: Transactor[Task] =
      Transactor.fromDriverManager[Task]("org.h2.Driver", "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", "user", "", None)

    sql"SELECT 42"
      .query[Int]
      .stream
      .transact(xa)
      .delayBy(1.second)
      .evalTap(i => Console.printLine(i))
      .compile
      .drain
      .exitCode
  }

Documentation

Learn more on the ZIO Interop Cats homepage!

Contributing

For the general guidelines, see ZIO contributor's guide.

Code of Conduct

See the Code of Conduct

Support

Come chat with us on Badge-Discord.

License

License

interop-cats's People

Contributors

adamgfraser avatar calvinlfer avatar danslapman avatar davesmith00000 avatar fristi avatar ghostdogpr avatar grouzen avatar guymers avatar johnspade avatar jorokr21 avatar jwojnowski avatar khajavi avatar kyri-petrou avatar lacarvalho91 avatar lemastero avatar mijicd avatar mindartur avatar mschuwalow avatar neko-kai avatar odomontois avatar regiskuckaertz avatar rtimush avatar scala-steward avatar sideeffffect avatar softinio avatar tomwadeson avatar ujali avatar vigoo avatar vkorchik avatar zeal18 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

interop-cats's Issues

Compatibility with zio 1.0.4

Moved from zio/zio#4581.

The following code fails with java.lang.NoSuchMethodError: zio.clock.package$.$anonfun$currentTime$3(Lscala/Function0;Lzio/Has;)Lzio/ZIO; with zio 1.0.4 and works with zio 1.0.3:

import zio._
import zio.clock._
import zio.interop.catz._
import java.util.concurrent._

Runtime.default.unsafeRunSync {
  cats.effect
    .Timer[ZIO[Clock, Any, *]]
    .clock
    .realTime(TimeUnit.MILLISECONDS)
}

Dependencies:

libraryDependencies ++= Seq(
  "org.typelevel" %% "cats-effect" % "2.3.1",
  "dev.zio" %% "zio" % "1.0.4",
  "dev.zio" %% "zio-interop-cats" % "2.2.0.1",
)

Scastie: https://scastie.scala-lang.org/FmuHgKbqSEaoGO96gkMBsA

This happened because of inlining from zio.*. A fix is to not inline from dependencies (#281).

Instance classes are recreated every time they're summoned

Because we're using implicit defs for type parameter polymorphism. We should cache the instances in lazy val and cast them, like some other libraries like monix do:

implicit def concurrentInstance[R]: Concurrent[RIO[R, *]] =
  concurrentInstance0.asInstanceOf[Concurrent[RIO[R, *]]

private[this] lazy val concurrentInstance0: Concurrent[RIO[Any, *]] = 
  new CatsConcurrent[Any]

Ambiguity during Arrow instance resolution for ZIO and ZManaged

The error is reproducible with the following code:

def getArrow[F[-_, +_, +_], R,E, A](f: F[R, E, A])(implicit a: ArrowChoice[F[*, E, *]]) = a

invocation: getArrow(ZIO.environment[Int])
compiler error: both method rioArrowInstance in class CatsInstances of type => cats.arrow.ArrowChoice[zio.RIO] [error] and method urioArrowInstance in class CatsInstances of type => cats.arrow.ArrowChoice[zio.URIO] [error] match expected type cats.arrow.ArrowChoice[[α$0$, γ$1$]zio.ZIO[α$0$,E,γ$1$]]
reason: both rioArrowInstance and urioArrowInstance are defined on the same level of priority
suggested fix: prioritize instances the following way : 1)RIO 2)URIO 3)ZIO (checked that it compiles on 2.13)

invocation: getArrow(ZManaged.environment[Int])
compiler error:found : cats.arrow.ArrowChoice[[α$15$, γ$16$]zio.ZManaged[α$15$,Nothing,γ$16$]] [error] required: cats.arrow.ArrowChoice[[α$0$, γ$1$]zio.ZManaged[α$0$,E,γ$1$]] [error] Note: [α$15$, γ$16$]zio.ZManaged[α$15$,Nothing,γ$16$] <: [α$0$, γ$1$]zio.ZManaged[α$0$,E,γ$1$], but trait ArrowChoice is invariant in type F
reason: no Arrow instances for ZManaged aliases containing 'Nothing' are defined.
suggested fix: define instances and prioritize them the following way : 1)RManaged 2)URManaged 3)ZManaged

Ambigous implicit values for `Sync`

While using http4s, the EntityEncoder has a constraint on F[_] : Sync when you import zio.interop.catz._ you will get this while compiling:

ambiguous implicit values:
  both method syncZManagedInstances in trait CatsEffectZManagedInstances of type [R]=> cats.effect.Sync[[γ$13$]zio.ZManaged[R,Throwable,γ$13$]]
  and method taskConcurrentInstance in trait CatsEffectInstances1 of type [R]=> cats.effect.Concurrent[[β$18$]zio.ZIO[R,Throwable,β$18$]]
  match expected type cats.effect.Sync[F]

This is with RC10

Scala 3.0.0-RC1 compatibility (ZIO 1.0.5)

With zio 1.0.5 just released with RC1 compatibility, building with the latest version of interop-cats gives conflicting cross-version errors. ZIO is unusable in when using dottyCompat dependency resolution, so there's no way to use interop-cats currently.

Resource toManaged throws with RC14

For me with zio RC19-1 and interop-cats RC14 and fs2-kafka 1.0.0 it throws at runtime an exception when I call Resource.toManaged

[info]     java.lang.NoSuchMethodError: 'cats.effect.Resource cats.effect.Resource.mapK(cats.arrow.FunctionK, cats.Defer, cats.Applicative)'
[info]     	at zio.interop.CatsIOResourceSyntax$.toManaged$extension(catszmanaged.scala:77)

Consider Providing Cats Core Instances More Directly

Right now if you want to get Cats instances for some ZIO data types you need to do import zio.interop.catz.core._ instead of import zio.interop.catz._. For example the Traverse instance for Chunk is not in scope without that import. Should we have catz directly extend these instances so the user can get everything they need in one import? Otherwise I worry it can be somewhat confusing for the user, especially since some Cats instances such as Monad for UIO are in scope without doing this because they are implemented by Cats Effect instances.

@neko-kai @ghostdogpr What do you think?

`cats.effect.Timer[IO[E, *]]` performance issue

As implemented, the instance for cats.effect.Timer[IO[E, *]] has poor performance as it calls provideLayer for each invocation of its own—and its nested cats.effect.Clock's—operations.

Benchmarks

The performance issue can be observed by comparing the benchmarks of a Cats Effect- with a ZIO-backed "Hello, World" http4s server.

Throughput achieved (measured with wrk -c16 -t2 -d1m http://localhost):

  • Cats Effect: 47,456.01 requests/sec
  • ZIO: 9,112.45 requests/sec

ZIO

package example

import org.http4s.HttpRoutes
import org.http4s.dsl.Http4sDsl
import org.http4s.implicits._
import org.http4s.server.blaze.BlazeServerBuilder
import zio.internal.Platform
import zio.interop.catz._
import zio.interop.catz.implicits._
import zio.{ExitCode, Task, URIO}

import scala.concurrent.ExecutionContext

object Http4sZioServer extends CatsApp {

  override val platform: Platform =
    Platform.benchmark

  override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = {

    val httpApp = {
      object dsl extends Http4sDsl[Task]
      import dsl._

      HttpRoutes.of[Task] {
        case GET -> Root => Ok("Hello, World!")
      }
    }.orNotFound

    val server =
      BlazeServerBuilder[Task](ExecutionContext.global)
        .bindHttp(8081, "0.0.0.0")
        .withHttpApp(httpApp)
        .resource

    server.toManaged.useForever
      .catchAll(err => zio.console.putStrLn(s"Error: $err").as(ExitCode.failure))
      .as(ExitCode.success)
  }
}

Cats Effect

package example

import cats.effect.{ExitCode, IO, IOApp}
import org.http4s.HttpRoutes
import org.http4s.dsl.Http4sDsl
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.implicits._

import scala.concurrent.ExecutionContext

object Http4sCatsEffectServer extends IOApp {

  override def run(args: List[String]): IO[ExitCode] = {

    val httpApp = {
      object dsl extends Http4sDsl[IO]
      import dsl._

      HttpRoutes.of[IO] {
        case GET -> Root => Ok("Hello, World!")
      }
    }.orNotFound

    val server =
      BlazeServerBuilder[IO](ExecutionContext.global)
        .bindHttp(8080, "0.0.0.0")
        .withHttpApp(httpApp)
        .resource

    server.use(_ => IO.never).as(ExitCode.Success)
  }
}

Cats Effect: Stream & Sink

Introduce an effect-polymorphic class atop ZStream & ZSink, with a default implementation for any Cats Effect data type (Cats IO, Monix Task, etc.).

package scalaz.zio.interop

trait Stream[F[_], +A] {
  ...
}
object Stream {
  ...
}

trait Sink[F[_], A, ...] { ... }
object Sink { ... }

The methods will all delegate to ZIO ZStream and ZSink, but they will take the ZIO effects returned by ZStream/ZSink methods and lift it into any effect F[_] that is suitable equipped.

Interop with skunk may die instead catch error

I use zio-interop-cats with skunk.

There is serializable transaction error occurs in postgres. I expect that catchAll should catch exception, but all application fails.

When usung cats.effect all errors are catched as expected.

This code is workaround, without it i cannot catch this error:

.sandbox
.catchAll { cause =>
  cause.defects.collectFirst {
    case e: PostgresErrorException =>
      if (e.code == "40001") ZIO.fail(new IllegalStateException("Serialization error occurs"))
      else ZIO.fail(e)
  }
    .getOrElse(
      ZIO.halt(cause)
    )
}

Please point me on how i can fix this.

Related issue in skunk's github is typelevel/skunk#438

test-skunk.zip

Version of zio-interop-cats should be 2.3.1.0 in example.

Error combinaison when using parXXX in cats

Hi,

It could be good when the error side is a semigroup, that we could do

val io1: IO[NonEmptyList[String], Unit] = IO.fail(NonEmptyList.of("Error 1"))
val io2: IO[NonEmptyList[String], Unit] = IO.fail(NonEmptyList.of("Error 2"))

val io3: IO[NonEmptyList[String], (Unit, Unit)] = (io1, io2).parTupled
// IO.fail(NonEmptyList.of("Error 1", "Error 2"))

This works in cats with eithers but not with zio at the moment. I would be happy to contribute on this one but I'm not sure to understand the code that is done in cats for the Parallel instance for Either.

Add ConcurrentEffect instance that auto-catches defects

Such an instance would be useful for compatibility with existing TF code that uses throw/catch outside of Sync#delay/Async#async where their behavior is undefined and left to the implementation, the default ZIO implementation of cats-effect typeclasses chooses to capture such exceptions as defects, which makes them unrecoverable with cats-effect's own methods.

This should be a separate instance, for example accessible at import zio.interop.catz.autocatch._

Care must be taken to suspend all places where potential defects may appear - that is at least all by-name parameters, ideally all super-class methods should be overriden to ensure that nothing is missed.

/cc @a14e

Bug: zio.Reservation cannot be cast to scala.Tuple2

This code:

   val Live: ZLayer[zio.ZEnv, Throwable, GSuiteSaml] = ZLayer.fromEffect {
    ZIO.runtime[Any] map { implicit rts =>
      val client: ZManaged[Any, Throwable, Client[Task]] =
        BlazeClientBuilder[Task](rts.platform.executor.asEC).resource.toManagedZIO
      new Service {
        override def submitRequest(uri: Uri, samlRequest: String): Task[String] = {
          client.use { c =>

produces the stack trace below. If I drop .toManagedZIO and use the cats effects Resource, all works.

╠─An unchecked error was produced.
║ java.lang.ClassCastException: zio.Reservation cannot be cast to scala.Tuple2
║ at zio.internal.FiberContext.evaluateNow(FiberContext.scala:844)
║ at zio.internal.FiberContext.$anonfun$fork$3(FiberContext.scala:706)
║ at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
║ at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
║ at java.lang.Thread.run(Thread.java:748)

║ Fiber:Id(1591194341124,11) was supposed to continue to:
║ a future continuation at zio.ZIO.run(ZIO.scala:1537)
║ a future continuation at zio.ZIO.bracket_(ZIO.scala:254)
║ a future continuation at zio.ZManaged.use(ZManaged.scala:994)
║ a future continuation at zio.ZIO.run(ZIO.scala:1537)
║ a future continuation at zio.ZManaged.use(ZManaged.scala:993)
║ a future continuation at zio.ZIO.bimap(ZIO.scala:223)
║ a future continuation at xxx.loginLogic(AuthRoute.scala:116)
║ a future continuation at xxx.AuthRoute.loginLogic(AuthRoute.scala:123)

Diverging implicit extension for UIO when importing cats instances

Scala will fail to compile code like this.

import cats.Monad
import cats.instances.either._
import scalaz.zio._
import scalaz.zio.interop.catz._

class ZIODiveringTest {
  Monad[UIO]
}

Removing the import for the either allows it to compile. Also works with option's instances. Does not happen for some reason when importing all instances.

Here is the error gotten

[error] D:\DevProjects\Stable\Ore\ore\app\ZIODiveringTest.scala:7:8: diverging implicit expansion for type cats.Monad[scalaz.zio.UIO]
[error] starting with method monoidZManagedInstances in trait CatsZManagedInstances
[error]   Monad[UIO]
[error]        ^

Version with Cats Effect

I think we should version this library with Cats Effect.

e.g. if you're using Cats Effect 1.0, then you pull in interop-cats 1.0.

We can use the micro version for backward-compatible updates within a Cats Effect version.

Thoughts?

Remove zio-test dependency

The latest version of this artifact has zio-test dependency.

[info]   +-dev.zio:zio-interop-cats_2.13:3.1.1.0 [S]
[info]     +-co.fs2:fs2-core_2.13:3.0.3 [S]
[info]     | +-org.scodec:scodec-bits_2.13:1.1.27 [S]
[info]     | +-org.typelevel:cats-core_2.13:2.6.1 [S]
[info]     | | +-org.typelevel:cats-kernel_2.13:2.6.1 [S]
[info]     | | +-org.typelevel:simulacrum-scalafix-annotations_2.13:0.5.4 [S]
[info]     | |
[info]     | +-org.typelevel:cats-effect_2.13:3.1.1 [S]
[info]     |   +-org.typelevel:cats-effect-kernel_2.13:3.1.1 [S]
[info]     |   | +-org.typelevel:cats-core_2.13:2.6.1 [S]
[info]     |   |   +-org.typelevel:cats-kernel_2.13:2.6.1 [S]
[info]     |   |   +-org.typelevel:simulacrum-scalafix-annotations_2.13:0.5.4 [S]
[info]     |   |
[info]     |   +-org.typelevel:cats-effect-std_2.13:3.1.1 [S]
[info]     |     +-org.typelevel:cats-effect-kernel_2.13:3.1.1 [S]
[info]     |       +-org.typelevel:cats-core_2.13:2.6.1 [S]
[info]     |         +-org.typelevel:cats-kernel_2.13:2.6.1 [S]
[info]     |         +-org.typelevel:simulacrum-scalafix-annotations_2.13:0.5.4 [S]
[info]     |
[info]     +-dev.zio:zio-streams_2.13:1.0.8 [S]
[info]     | +-dev.zio:zio_2.13:1.0.8 [S]
[info]     |   +-dev.zio:izumi-reflect_2.13:1.1.2 [S]
[info]     |   | +-dev.zio:izumi-reflect-thirdparty-boopickle-shaded_2.13:1.1.2 [S]
[info]     |   |
[info]     |   +-dev.zio:zio-stacktracer_2.13:1.0.8 [S]
[info]     |
[info]     +-dev.zio:zio-test_2.13:1.0.8 [S]
[info]     | +-dev.zio:zio-streams_2.13:1.0.8 [S]
[info]     | | +-dev.zio:zio_2.13:1.0.8 [S]
[info]     | |   +-dev.zio:izumi-reflect_2.13:1.1.2 [S]
[info]     | |   | +-dev.zio:izumi-reflect-thirdparty-boopickle-shaded_2.13:1.1.2 [S]
[info]     | |   |

BuildInfo class collides with BuildInfo from ZIO

This causes problems for example when generating assemblies:

[error] 1 error was encountered during merge
[error] java.lang.RuntimeException: deduplicate: different file contents found in the following:
[error] /Users/mlanger/.ivy2/cache/dev.zio/zio-interop-cats_2.12/jars/zio-interop-cats_2.12-1.3.1.0-RC3.jar:zio/BuildInfo$.class
[error] /Users/mlanger/.ivy2/cache/dev.zio/zio_2.12/jars/zio_2.12-1.0.0-RC10-1.jar:zio/BuildInfo$.class

This issue can be fixed easily by adapting the following line:

buildInfoPackage := "zio",

Scala3

I'm trying to use the Zio ecosystem with scala3 and running into this situation:

  • Zio built for scala 2.13 doesn't work with scala 3
  • A project using Zio built for scala 3 that has transitive dependencies on Zio for 2.13 (via zio-interop-cats for 2.13) will get "Modules were resolved with conflicting cross-version suffixes" errors

Is there a workaround or a prerelease that can work with scala3?

MonadError.map should not directly translate to zio.map

I'm just trying to integrate a lib (https://github.com/bot4s/telegram/) that uses cats effect and I'm using the interop-cats module to get hold off a CatsMonadError.

The library uses map(f)
(
https://github.com/bot4s/telegram/blob/c40d679be5865d1a5caa897e0c0f2307922a0cca/core/src/com/bot4s/telegram/clients/SttpClient.scala#L79-L81
) where f can throw an exception ( https://github.com/bot4s/telegram/blob/c40d679be5865d1a5caa897e0c0f2307922a0cca/core/src/com/bot4s/telegram/api/RequestHandler.scala#L113-L120) .

In my local app, I've now overridden the map in

override final def pure[A](a: A): ZIO[R, E, A] = ZIO.succeedNow(a)
override final def map[A, B](fa: ZIO[R, E, A])(f: A => B): ZIO[R, E, B] = fa.map(f)

from

  override final def map[A, B](fa: ZIO[R, E, A])(f: A => B): ZIO[R, E, B]                = fa.map(f)

to

  override final def map[A, B](fa: ZIO[R, E, A])(f: A => B): ZIO[R, E, B]                = fa.flatMap(v => ZIO.effect(f(v)))

I'm also wondering if

  override final def pure[A](a: A): ZIO[R, E, A]                                         = ZIO.succeedNow(a)

should be really implemented this way, as I've noticed that ,e.g. the library is using stuff like
monadError.pure(logger.debug("blabla")) so I think it should be

  override final def pure[A](a: A): ZIO[R, E, A]                                         = ZIO.efffect(a)

( https://github.com/bot4s/telegram/blob/c40d679be5865d1a5caa897e0c0f2307922a0cca/core/src/com/bot4s/telegram/api/RequestHandler.scala#L34-L37 )

As I'm in no way an expert in this area, any advice would be greatly appreciated!

To integrate with the library, I've created the following class in my project:

import zio.{ZEnv, ZIO}
import cats.{MonadError => CMonadError}
import com.softwaremill.sttp.{
  Request,
  Response,
  SttpBackend,
  MonadAsyncError => SttpMonadAsyncError,
  MonadError => SttpMonadError
}
import zio.{Task, ZIO}

import scala.concurrent.Future


object ZIOSttp {
  type MyEffect[T] = ZIO[ZEnv, Throwable, T]

  case class ZIOSttpBackendWrapper[S](underlying: SttpBackend[Future, S]) extends SttpBackend[MyEffect, S] {
    override def send[T](request: Request[T, S]): MyEffect[Response[T]] = ZIO.fromFuture(ec => underlying.send(request))
    override def close(): Unit = underlying.close()
    override def responseMonad: SttpMonadError[MyEffect] = sttpMyEffectMonadError
  }


  implicit val sttpMyEffectMonadError: SttpMonadError[MyEffect] = new SttpMonadAsyncError[MyEffect] {
    override def async[T](register: (Either[Throwable, T] => Unit) => Unit): Task[T] = for {
        p <- zio.Promise.make[Throwable, T]
        _ = register {
          case Left(t) => p.fail(t)
          case Right(v) => p.succeed(v)
        }
        v <- p.await
      } yield v

    override def unit[T](t: T): MyEffect[T] = Task.effect(t)
    override def map[T, T2](fa: MyEffect[T])(f: T => T2): MyEffect[T2] = fa.flatMap(e => ZIO.effect(f(e)))
    override def flatMap[T, T2](fa: MyEffect[T])(f: T => MyEffect[T2]): MyEffect[T2] = fa.flatMap(f)
    override def error[T](t: Throwable): MyEffect[T] = ZIO.fail(t)
    override protected def handleWrappedError[T](rt: MyEffect[T])(h: PartialFunction[Throwable, MyEffect[T]]): MyEffect[T] = rt.catchAll(h)
  }


  def wrappedMonadError(): CMonadError[MyEffect, Throwable] = zio.interop.catz.monadErrorInstance.asInstanceOf[CMonadError[MyEffect, Throwable]]

  implicit def myEffectMonadError(): CMonadError[MyEffect, Throwable] = new CMonadError[MyEffect, Throwable] {

    override def map[A, B](fa: MyEffect[A])(f: A => B): MyEffect[B] = fa.flatMap(v => ZIO.effect(f(v)))

    override def raiseError[A](e: Throwable): MyEffect[A] = wrappedMonadError().raiseError(e)

    override def handleErrorWith[A](fa: MyEffect[A])(f: Throwable => MyEffect[A]): MyEffect[A] = fa.catchAll(e => f(e))

    override def pure[A](x: A): MyEffect[A] = ZIO.effect(x)

    override def flatMap[A, B](fa: MyEffect[A])(f: A => MyEffect[B]): MyEffect[B] = fa.flatMap(f)

    override def tailRecM[A, B](a: A)(f: A => MyEffect[Either[A, B]]): MyEffect[B] = wrappedMonadError().tailRecM(a)(f)
  }

}

Cats Effect: Queue

Introduce an effect-polymorphic class atop ZQueue, with a default implementation for any Cats Effect data type (Cats IO, Monix Task, etc.).

package scalaz.zio.interop

trait Queue[F[_], +A] {
  ...
}
object Queue {
  ...
}

The methods will all delegate to ZIO ZQueue, but they will take the ZIO effect returned by ZQueue methods and lift it into any effect F[_] that is suitable equipped.

ApplicativeAsk with subtyping for ZIO

Motivation:
R in ZIO[R, .., ..] frequently holds complex environments (Has[A] with Has[B] with ...) while ApplicativeAsk designed to be an atomic context bound (ApplicativeAsk[F, Has[A]]). Currently interop-cats provides only ApplicativeLocal instance for the whole invironment, which is inconvenient in many cases.

Proposal:
add an ApplicativeAsk instance with support of subtyping, something like that:

implicit def zioApplicativeAsk[R1, R <: R1, E](implicit ev: Applicative[ZIO[R, E, ?]]): ApplicativeAsk[ZIO[R, E, ?], R1] =
    new DefaultApplicativeAsk[ZIO[R, E, ?], R1] {
      override val applicative: Applicative[ZIO[R, E, *]] = ev
      override def ask: ZIO[R, E, R1] = ZIO.environment
    }

I already started to work on PR with subtyping instance, but it will be ambiguous to existing ApplicatioveLocal instance

java.lang.NoSuchMethodError: cats.effect.ContextShift.$init$(Lcats/effect/ContextShift;)

I am using the latest ZIO and ZIOInteropCats Version and get a MethodNotFoundException when using the Transactor vom Doobie.

build.sbt

scalaVersion := "2.12.8"

val ZIOVersion = "1.0.0-RC11-1"
val ZIOInteropCats = "2.0.0.0-RC2"

libraryDependencies ++= Seq(
  // ZIO
  "dev.zio" %% "zio"  % ZIOVersion,
  "dev.zio" %% "zio-streams" % ZIOVersion,
  "dev.zio" %% "zio-interop-cats" % ZIOInteropCats,
  "org.tpolecat" %% "doobie-core"      % "0.7.0",
  "org.tpolecat" %% "doobie-postgres"  % "0.7.0",
...

DoobieTweetRepo.scala

import doobie.implicits._
import doobie.util.transactor.Transactor
import zio._
import zio.interop.catz._
...
object DoobieTweetRepo {

  // this is line 40
  def xa(db: DBConfig): Transactor[Task]  = Transactor.fromDriverManager[Task](
    "org.postgresql.Driver", db.url, db.username, db.password
  )

}

Error

java.lang.NoSuchMethodError: cats.effect.ContextShift.$init$(Lcats/effect/ContextShift;)V
zio-twitter-test[ERROR] 	at zio.interop.CatsInstances$$anon$3.<init>(catsjvm.scala:54)
zio-twitter-test[ERROR] 	at zio.interop.CatsInstances.zioContextShift(catsjvm.scala:54)
zio-twitter-test[ERROR] 	at com.rocketsolutions.db.DoobieTweetRepo$.xa(DoobieTweetRepo.scala:40)
zio-twitter-test[ERROR] 	at com.rocketsolutions.TwitterDemo$$anon$1.transactor(TwitterDemo.scala:53)
zio-twitter-test[ERROR] 	at com.rocketsolutions.db.DoobieTweetRepo$$anon$1.initTable(DoobieTweetRepo.scala:24)
zio-twitter-test[ERROR] 	at com.rocketsolutions.TwitterDemo$.$anonfun$main$1(TwitterDemo.scala:42)
zio-twitter-test[ERROR] 	at zio.internal.FiberContext.evaluateNow(FiberContext.scala:471)
zio-twitter-test[ERROR] 	at zio.internal.FiberContext.$anonfun$fork$1(FiberContext.scala:604)
zio-twitter-test[ERROR] 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
zio-twitter-test[ERROR] 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
zio-twitter-test[ERROR] 	at java.lang.Thread.run(Thread.java:748)

Any idea?

Support ZIO Test

We should have a test package you can import that will let you run arbitrary F[_] tests for any effect monad, by tying in ZIO interruption to F[_] interruption, asynchronous conversion.

  • testF
  • checkF
  • checkSomeF
  • checkAllF

Any others?

Ambiguous ZManaged implicit instances

Hello, upon upgrade to RC9 (from RC7) I started getting

ambiguous implicit values:
[error] both method syncZManagedInstances in trait CatsEffectZManagedInstances of type [R]=> cats.effect.Sync[[γ$13$]zio.ZManaged[R,Throwable,γ$13$]]
[error] and method taskConcurrentInstance in trait CatsEffectInstances1 of type [R]=> cats.effect.Concurrent[[β$18$]zio.ZIO[R,Throwable,β$18$]]

I'll update the issue when I discover more info or solve the issue

Compatibility with TestClock

While writing tests for ZIO-wrapped fs2.Stream code, I discovered that using TestClock.adjust or similar has no effect on the Timer[Task] instance made available through zio.interop.catz.implicits.

A reproducer (though Scastie doesn't let me choose any newer version of the interop package than 1.0.3, so it won't run): https://scastie.scala-lang.org/q1qeLLL9Rty3E0NPT0izGQ

@adamgfraser had this to say:
Yes I think that is an issue. The problem seems to be that in interop-cats the Timer instance uses the live Clock so like in your example the stream you are creating using the live clock. This makes sense in general because the Cats Effect types can't require an environment so we need to provide something and the live one makes the most sense, though it doesn't work for your use case. I think what we could probably do there is create a helper method to create a Cats Effect Timer and Clock from a ZIO Clock. Then you could access the Clock in the environment, which would be the TestClock, and use it to define a new implicit Timer instance that would use that. Do you want to open an issue for that in interop-cats?

Bad interaction between doobie's unique and ZIO.either

If a unique doobie select fails because the row does not exist, and that Task is turned into an UIO via either, the result is not a Left as I would have expected, but an Exception is thrown.

I don't think the problem is with doobie - when using cats-effect instead of zio the behavior is as expected.

import utest._
import doobie._
import doobie.implicits._
import zio._
import zio.interop.catz._


object DoobieUniqueTest extends TestSuite {

  val runtime = new DefaultRuntime {}
  val xa = Transactor.fromDriverManager[Task]("org.sqlite.JDBC", "jdbc:sqlite:memory:demo.db", "", "")

  val tests = Tests {
    test("Find non-existing user") {
      val x = runtime.unsafeRun(createAndFailToFind())
      assert(x.isLeft)
    }
  }

  def createAndFailToFind(): UIO[Either[Throwable, (PasswordHash, String)]] =
    (createTable() *> findUser("nosuchuser")).either


  def createTable(): Task[Int] =
     sql"""create table if not exists passwd (
          |  username varchar primary key,
          |  hash varchar
          |  );
          |  """.stripMargin
       .update.run.transact(xa)

  def findUser(username: String): Task[(PasswordHash, String)] =
    for {
      hash <- sql"""select hash from passwd where username=$username"""
        .query[String]
        .unique
        .transact(xa)
      x <-  Task(upickle.default.read[(PasswordHash, String)](hash))
    } yield x
}

This fails with the following error:

X me.gmeiner.stoic.server.auth.DoobieUniqueTest.Find non-existing user 1827ms
zio.FiberFailure: Fiber failed.
An unchecked error was produced.
doobie.util.invariant$UnexpectedEnd$: ResultSet exhausted; more rows expected.
at doobie.util.invariant$UnexpectedEnd$.(invariant.scala)
at doobie.hi.resultset$.$anonfun$getUnique$1(resultset.scala:195)
at doobie.hi.resultset$.$anonfun$getUnique$1$adapted(resultset.scala:192)
at cats.SemigroupalArityFunctions.$anonfun$map2$1(SemigroupalArityFunctions.scala:30)
at cats.Monad.$anonfun$map$1(Monad.scala:16)
at cats.free.Free.$anonfun$step$1(Free.scala:52)
at cats.free.Free.step(Free.scala:53)
at cats.free.Free.$anonfun$foldMap$1(Free.scala:153)
at cats.data.KleisliFlatMap.$anonfun$tailRecM$2(Kleisli.scala:534)
at zio.interop.CatsMonad.$anonfun$tailRecM$1(catsjvm.scala:252)
at zio.ZIOFunctions.$anonfun$suspend$1(ZIO.scala:1444)
at zio.internal.FiberContext.evaluateNow(FiberContext.scala:485)
at zio.Runtime.unsafeRunAsync(Runtime.scala:94)
at zio.Runtime.unsafeRunAsync$(Runtime.scala:80)
at me.gmeiner.stoic.server.auth.DoobieUniqueTest$$anon$1.unsafeRunAsync(DoobieUniqueTest.scala:12)
at zio.Runtime.unsafeRunSync(Runtime.scala:69)
at zio.Runtime.unsafeRunSync$(Runtime.scala:66)
at me.gmeiner.stoic.server.auth.DoobieUniqueTest$$anon$1.unsafeRunSync(DoobieUniqueTest.scala:12)
at zio.Runtime.unsafeRun(Runtime.scala:58)
at zio.Runtime.unsafeRun$(Runtime.scala:57)
at me.gmeiner.stoic.server.auth.DoobieUniqueTest$$anon$1.unsafeRun(DoobieUniqueTest.scala:12)
at me.gmeiner.stoic.server.auth.DoobieUniqueTest$.$anonfun$tests$2(DoobieUniqueTest.scala:17)

`LiftIO` instance does not respect cancelation

The current implementation does not use the cancelation token in case of interruption:

private class ZioLiftIO[R](implicit runtime: IORuntime) extends LiftIO[RIO[R, *]] {
override final def liftIO[A](ioa: CIO[A]): RIO[R, A] =
ZIO.effectAsync(k => ioa.unsafeRunAsync(k.compose(ZIO.fromEither(_))))
}

The impl should be rewritten to something like this:

ZIO.effectAsyncInterrupt { cb =>
  val (fa, canceler) = ioa.unsafeToFutureCancelable()
  cb(ZIO.fromFuture(_ => fa))
  Left(ZIO.fromFuture(_ => canceler()).orDie)
}

Arbitrary/Eq instances for ZIO should be published

The files below are super useful for implementing prop-based tests but they cannot be included as an external dependency. only copy-pasted:
catzSpecBase.scala
catzSpecZIOBase.scala
GenIOInteropCats.scala

Issue using 2.1.3.0-RC15 with ZIO 1.0.0-RC21

I assume this is due to fibre supervision changes:

Exception in thread "zio-default-async-4-667346055" java.lang.NoSuchMethodError: 'void zio.ZIO$Fork.<init>(zio.ZIO)'
	at zio.interop.CatsConcurrentEffect.$anonfun$runCancelable$2(cats.scala:204)
	at zio.Runtime.unsafeRunAsyncCancelable(Runtime.scala:125)
	at zio.Runtime.unsafeRunAsyncCancelable$(Runtime.scala:105)
	at zio.Runtime$$anon$3.unsafeRunAsyncCancelable(Runtime.scala:247)
	at zio.Runtime.unsafeRunAsync(Runtime.scala:94)
	at zio.Runtime.unsafeRunAsync$(Runtime.scala:93)
	at zio.Runtime$$anon$3.unsafeRunAsync(Runtime.scala:247)
	at zio.interop.CatsConcurrentEffect.$anonfun$runCancelable$1(cats.scala:206)
	at cats.effect.internals.IORunLoop$.step(IORunLoop.scala:193)
	at cats.effect.IO.unsafeRunTimed(IO.scala:327)
	at cats.effect.IO.unsafeRunSync(IO.scala:246)
	at cats.effect.SyncIO.unsafeRunSync(SyncIO.scala:51)
	at org.http4s.server.blaze.Http1ServerStage$$anon$2.run(Http1ServerStage.scala:186)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
	at java.base/java.lang.Thread.run(Thread.java:832)

Issue with fs2-blobstore and ZIO

fs2-blobstore is a library which has a Store abstraction for storing blobs. The nice thing is that you can easily swap an implementation, this is useful during testing (local) and migrating to other blob stores.

We use it in a app where we also use ZIO and since the interop-cats module I would not expect any problems, yet it seems there is an issue which seems to be ZIO specific.

While downloading a file, from time to time it seems the download is incomplete. After checking the logs I found out:

java.lang.Error: received record [java.nio.HeapByteBuffer[pos=0 lim=2875 cap=2875]] in invalid state [UpstreamCompletion]

It seems that the FSM being used in the fs2-reactivestreams interop is already completed (state: UpstreamCompletion), while another chunk of bytes is still sent in that state causing that error.

I already verified that this is not an issue in the fs2-blobstore implementation by writing a property test: fs2-blobstore/fs2-blobstore#334

I've created a reproduction case in a repository here: https://github.com/vectos/zio-fs2-blobstore-issue/

Port for CE3

Cats-effect 3 final will be out soon including a major redesign of the type classes.
I am working on this, but we will probably need another branch to be able to also maintain the CE2 interop.

Fiber is failed if http4s request is cancelled

I faced with an issue that an error message appears in logs saying that fiber is failed when the client request is canceled. Another similar issue was fixed in pr #113.

I am expecting that the cancellation of requests should not produce an error message in logs and assuming that an issue in zio.interop.CatsConcurrentEffect#runCancelable, though I'm not sure.

I tested this with cats-effect IO and the error was not logged.
I also tested it with ZIO-RC17 and the behavior was the same as with RC18 (the error was logged).

Libraries versions:

org.http4s::http4s-blaze-server:0.21.1
org.http4s::http4s-dsl:0.21.1
dev.zio::zio:1.0.0-RC18
dev.zio::zio-interop-cats:2.0.0.0-RC11

Here's the sample code:

object MainTest extends CatsApp {
  override def run(args: List[String]) =
    BlazeServerBuilder[Task]
      .bindHttp(8030, "0.0.0.0")
      .withHttpApp(
        HttpRoutes
          .of[Task] { case _ => Task(Thread.sleep(100000)) *> Task(Response(Status.Ok)) }
          .orNotFound
      )
      .serve
      .compile
      .drain
      .as(0)
      .orElse(ZIO.succeed(1))
}

With cancelled get request:

❯ curl "http://localhost:8030"
^C⏎

Produces the following logs:

[DEBUG] 2020-03-06 14:10:26.146 SelectorLoop - Channel initialized.
[INFO ] 2020-03-06 14:10:26.149 BlazeServerBuilder - 
  _   _   _        _ _
 | |_| |_| |_ _ __| | | ___
 | ' \  _|  _| '_ \_  _(_-<
 |_||_\__|\__| .__/ |_|/__/
             |_|
[INFO ] 2020-03-06 14:10:26.207 BlazeServerBuilder - http4s v0.21.1 on blaze v0.14.11 started at http://[::]:8030/
[DEBUG] 2020-03-06 14:10:35.727 SelectorLoop - Channel initialized.
[DEBUG] 2020-03-06 14:10:35.728 NIO1HeadStage - Starting up.
[DEBUG] 2020-03-06 14:10:35.728 NIO1HeadStage - Stage NIO1HeadStage sending inbound command: Connected
[DEBUG] 2020-03-06 14:10:35.728 Http1ServerStage$$anon$1 - Starting HTTP pipeline
[DEBUG] 2020-03-06 14:10:35.730 IdleTimeoutStage - Starting idle timeout stage with timeout of 60000 ms
[DEBUG] 2020-03-06 14:11:35.803 IdleTimeoutStage - Idle timeout after 60000 ms.
[DEBUG] 2020-03-06 14:11:35.803 Http1ServerStage$$anon$1 - Shutting down due to idle timeout
[DEBUG] 2020-03-06 14:11:35.804 Http1ServerStage$$anon$1 - Shutting down HttpPipeline
[DEBUG] 2020-03-06 14:11:35.813 Http1ServerStage$$anon$1 - Shutting down.
[DEBUG] 2020-03-06 14:11:35.813 IdleTimeoutStage - Shutting down idle timeout stage
[DEBUG] 2020-03-06 14:11:35.813 IdleTimeoutStage - Shutting down.
[DEBUG] 2020-03-06 14:11:35.813 NIO1HeadStage - Shutting down.
[DEBUG] 2020-03-06 14:11:35.814 IdleTimeoutStage - Shutting down idle timeout stage
[DEBUG] 2020-03-06 14:11:35.814 IdleTimeoutStage - Shutting down.
[DEBUG] 2020-03-06 14:11:35.814 IdleTimeoutStage - Removed mid-stage: IdleTimeoutStage
[DEBUG] 2020-03-06 14:11:35.815 NIO1HeadStage - Stage NIO1HeadStage sending inbound command: Disconnected
[DEBUG] 2020-03-06 14:11:35.815 Http1ServerStage$$anon$1 - Shutting down HttpPipeline
[DEBUG] 2020-03-06 14:11:35.816 Http1ServerStage$$anon$1 - Shutting down.
[ERROR] 2020-03-06 14:11:35.861 Http1ServerStage$$anon$1 - Error running request: Request(method=GET, uri=/, headers=Headers(Host: localhost:8030, User-Agent: curl/7.64.1, Accept: */*))
zio.FiberFailure: Fiber failed.
╥
╠─An interrupt was produced by #32.
║ No ZIO Trace available.
║
╠─An interrupt was produced by #33.
║ No ZIO Trace available.
▼
[DEBUG] 2020-03-06 14:11:35.875 Http1ServerStage$$anon$1 - closeConnection()
[DEBUG] 2020-03-06 14:11:35.875 Http1ServerStage$$anon$1 - Shutting down HttpPipeline
[DEBUG] 2020-03-06 14:11:35.875 Http1ServerStage$$anon$1 - Shutting down.
[DEBUG] 2020-03-06 14:11:35.875 Http1ServerStage$$anon$1 - Shutting down HttpPipeline
[DEBUG] 2020-03-06 14:11:35.875 Http1ServerStage$$anon$1 - Shutting down.
[DEBUG] 2020-03-06 14:11:35.875 NIO1HeadStage - Shutting down.
[DEBUG] 2020-03-06 14:11:35.876 NIO1HeadStage - Stage NIO1HeadStage sending inbound command: Disconnected
[DEBUG] 2020-03-06 14:11:35.876 Http1ServerStage$$anon$1 - Shutting down HttpPipeline
[DEBUG] 2020-03-06 14:11:35.876 Http1ServerStage$$anon$1 - Shutting down.

NoSuchMedhod fromNanos

val zio = "1.0.0-RC18-1+27-ac79039b-SNAPSHOT"
val zioInteropCats = "2.0.0.0-RC11+1-87261427-SNAPSHOT"

An unchecked error was produced.
root ║ java.lang.NoSuchMethodError: 'zio.duration.Duration$Finite zio.duration.Duration$.fromNanos(long)'
root ║ 	at zio.interop.CatsEffectInstances$$anon$4.$anonfun$sleep$2(cats.scala:88)
root ║ 	at zio.clock.package$.$anonfun$sleep$3(package.scala:86)
root ║ 	at zio.internal.FiberContext.evaluateNow(FiberContext.scala:517)
root ║ 	at zio.internal.FiberContext.$anonfun$fork$2(FiberContext.scala:681)
root ║ 	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
root ║ 	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
root ║ 	at java.base/java.lang.Thread.run(Thread.java:834)

I can provide full stack but this seemed relevant. Thank you.

Separate interop with cats-core

Hi,

I think it would it make sense to have a separate package for interop only with cats-core (excluding cats-effect). That way if I am only using cats-core for functional goodness, I wouldn't need to bring in cats-effect as a transitive dependency into my build.

Thoughts?

Cats Effect: Schedule

Introduce an effect-polymorphic class atop ZSchedule, with a default implementation for any Cats Effect data type (Cats IO, Monix Task, etc.).

package scalaz.zio.interop

trait Schedule[F[_], -A, +B] {
  ...
}
object Schedule {
  def never[F[_]: ConcurrentEffect]: Schedule[F, Any, Nothing] = ???
}

The methods will all delegate to ZSchedule, but they will take the ZIO effect returned by ZSchedule methods and lift it into any effect F[_] that is suitable equipped.

Ambiguous implicits for cats.effect.Effect[UIO]

Using cats interop with zio.Task works perfectly, but I cannot get a cats.effect.Effect for zio.UIO - which afaik should work as well.

Given the following example:

import zio._
import zio.interop.catz._

implicit def r = zio.Runtime.default
val F: cats.effect.Effect[Task] = implicitly // compiles
val FX: cats.effect.Effect[UIO] = implicitly // error

For the latter one, I get a compile error:

[error] ambiguous implicit values:
[error]  both method $conforms in object Predef of type [A]=> A => A
[error]  and method zioContextShift in class CatsEffectInstances of type [R, E]=> cats.effect.ContextShift[[γ$6$]zio.ZIO[R,E,γ$6$]]
[error]  match expected type T
[error]   val FX: cats.effect.Effect[UIO] = implicitly
[error]                                     ^
[info] Unit <: cats.effect.Effect[zio.UIO]?
[info] false

Any ideas?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.