cats-effect
cats-effect copied to clipboard
Add different effect init for `Random`/`SecureRandom`
I would like to be able to initialize Random in a different effect, as it's in Ref and Deffered (def in[F, G, A]). Motivation:
- I can't use transformer implicits, because I want to initialize
Random, for example, inConnectionIO(type fromDoobie, which has implementation ofSyncforConnectionIO). - I don't want to use
mapKbecause it would be incorrect and expensive for implementation (ex: provided by libmapKforConnectionIOuses aDispatcherthat runs the logic, which adds additional costs for lift and unlift fromIO)
Below is a sample code for Ref, I would like to be able to do exactly the same for Random and SecureRandom.
import cats.FlatMap
import cats.effect.std.Console
import cats.effect.{Ref, Sync}
import cats.syntax.all.*
class Foo[F[_]: FlatMap: Console](ref: Ref[F, Int]) {
def print: F[Unit] = ref.get.flatMap(Console[F].println)
}
def foo[I[_]: Sync, F[_]: Sync: Console]: I[Foo[F]] =
for {
ref <- Ref.in[I, F, Int](0)
/// Init some classes in F
} yield new Foo(ref)
Proposal:
I looked at current implementation javaSecuritySecureRandom, and it can be divided into 2 effects. So, new method will have signature like this:
// Proposal - add new method
def javaSecuritySecureRandomIn[I[_]: Sync, F[_]: Sync](n: Int): I[SecureRandom[F]]
// Current impl
def javaSecuritySecureRandom[F[_]: Sync](n: Int): F[SecureRandom[F]]
Someone recently opened a PR for this, but I think it needs to be finished up:
- https://github.com/typelevel/cats-effect/pull/4338
I don't want to use
mapKbecause it would be incorrect and expensive for implementation (ex: provided by libmapKforConnectionIOuses aDispatcherthat runs the logic, which adds additional costs for lift and unlift fromIO)
How would it be incorrect?
Regarding performance: actually,ConnectionIO's liftK will not use a Dispatcher in this case, since the entire operation can be directly interpreted with syncStep.
- https://github.com/typelevel/doobie/pull/1906
be directly interpreted with
syncStep
It dosn't work for effects ex (result - "Left"):
import cats.effect.unsafe.implicits.global
import cats.effect.{Async, IO}
import java.util.UUID
Async[IO].syncStep[IO, UUID](IO.randomUUID, Int.MaxValue).flatMap {
case Left(_) => IO.println(s"Left") // Can't run - use Dispatcher
case Right(_) => IO.println(s"Right")
}.unsafeRunSync()
Someone recently opened a PR for this, but I think it needs to be finished up:
Thx, I didn't see it (I watched only issue). I could complete that PR, but it would be difficult to access (branch is in a personal fork). Therefore, I suggest that I open a new MR with suggested edits and comments fixses from previous PR. (before that, I'll ask author if he's ready to finish PR, or if he'll let me finish it)
It dosn't work for effects ex (result -
"Left"):
Hmm, are you sure? This program prints "Right" for me.
//> using dep org.typelevel::cats-effect::3.6.1
import cats.effect.*
import java.util.UUID
object App extends IOApp.Simple:
def run = Async[IO]
.syncStep[IO, UUID](IO.randomUUID, Int.MaxValue)
.flatMap {
case Left(_) => IO.println(s"Left") // Can't run - use Dispatcher
case Right(_) => IO.println(s"Right")
}
Therefore, I suggest that I open a new MR with suggested edits and comments fixses from previous PR.
Yes, that's the way to go, thanks!
Hmm, are you sure?
Yes) For me it's Left... Ok, i'll try to minimize that behavior (for me - run in sbt, jvm temurin 21, windows 11); some of my friends say that they have Left, and some have Right