Packages

  • package root
    Definition Classes
    root
  • package izumi
    Definition Classes
    root
  • package functional
    Definition Classes
    izumi
  • package bio

    Current hierarchy (rendered: https://izumi.7mind.io/bio/media/bio-relationship-hierarchy.svg, use https://www.nomnoml.com/ to render)

    Current hierarchy (rendered: https://izumi.7mind.io/bio/media/bio-relationship-hierarchy.svg, use https://www.nomnoml.com/ to render)

    [Functor2]<--[Bifunctor2]
    [Bifunctor2]<--[ApplicativeError2]
    [Functor2]<--[Applicative2]
    [Applicative2]<--[Guarantee2]
    [Applicative2]<--[Monad2]
    [Guarantee2]<--[ApplicativeError2]
    [ApplicativeError2]<--[Error2]
    [Error2]<--[WeakTemporal2]
    [WeakTemporal2]<--[Temporal2]
    [Monad2]<--[Error2]
    [Error2]<--[Bracket2]
    [Bracket2]<--[Panic2]
    [Panic2]<--[IO2]
    [IO2]<--[WeakAsync2]
    [WeakAsync2]<--[Async2]
    
    [Monad2]<--[Parallel2]
    [Parallel2]<--[WeakAsync2]
    [Panic2]<--[Concurrent2]
    [Parallel2]<--[Concurrent2]

    Auxiliary algebras:

    [cats.effect.*]<:--[CatsConversions]
    
    [Fork2]<:--[Fiber2]
    
    [BlockingIO2]
    
    [Primitives2]
    
    [Primitives2]<:--[Ref2]
    [Primitives2]<:--[Semaphore2]
    [Primitives2]<:--[Promise2]
    
    [PrimitivesM2]
    [PrimitivesM2]<:--[RefM2]
    [PrimitivesM2]<:--[Mutex2]
    
    [Entropy1]<:--[Entropy2]
    [Clock1]<:--[Clock2]
    
    [UnsafeRun2]

    Raw inheritance hierarchy:

    [Bifunctor2]<--[ApplicativeError2]
    [Functor2]<--[Applicative2]
    [Applicative2]<--[Guarantee2]
    [Applicative2]<--[Monad2]
    [Guarantee2]<--[ApplicativeError2]
    [ApplicativeError2]<--[Error2]
    [Monad2]<--[Error2]
    [Error2]<--[Bracket2]
    [Bracket2]<--[Panic2]
    [Panic2]<--[IO2]
    
    [Parallel2]<--[WeakAsync2]
    [Parallel2]<--[Concurrent2]
    [Concurrent2]<--[Async2]
    [IO2]<--[WeakAsync2]
    [WeakAsync2]<--[Async2]
    
    [WeakTemporal2]<--[Temporal2]

    current hierarchy roots:

    bifunctor:

    standalone:

    Definition Classes
    functional
    Note

    New BIO typeclass checklist:

    [ ] - add syntax to `Syntax2` with the same name as the type
    [ ] - add syntax for new root's `InnerF` with the same name as `InnerF` in `Syntax2`
    [ ] - add new attachments in `RootInstanceLowPriority*`
    [ ] - add conversion from itself to its `InnerF` to `RootInstanceLowPriority*`
          (conversions implicit priority: from most specific `InnerF` to least specific)
    [ ] - add conversion to equivalent cats typeclass if applicable in `CatsConversions`
    [ ] - update hierarchy graph above, re-render SVG
    [ ] - add syntax tests in `SyntaxTest`, runtime tests if applicable
    ,

    Real and raw (direct inheritance) hierarchies differ because of implicit ambiguities caused by inheritance: https://typelevel.org/blog/2016/09/30/subtype-typeclasses.html However, since Scala 3.7, the ambiguity problem has been resolved on Scala 3 using inverted given prioritization: https://contributors.scala-lang.org/t/joining-the-dots-on-recent-implicit-prioritization-changes-and-some-scala-history/6814/3 So, when or if we drop support for Scala 2, we can revisit the design, remove InnerF pattern and make real and raw hierarchy match.

  • package lifecycle
    Definition Classes
    functional
  • Lifecycle
  • LifecycleAggregator
  • package quasi
    Definition Classes
    functional

package lifecycle

Linear Supertypes
AnyRef, Any
Ordering
  1. Alphabetic
  2. By Inheritance
Inherited
  1. lifecycle
  2. AnyRef
  3. Any
  1. Hide All
  2. Show All
Visibility
  1. Public
  2. Protected

Type Members

  1. trait Lifecycle[+F[_], +A] extends AnyRef

    Lifecycle is a class that describes the effectful allocation of a resource and its finalizer.

    Lifecycle is a class that describes the effectful allocation of a resource and its finalizer. This can be used to represent expensive resources.

    Resources can be created using Lifecycle.make:

    def open(file: File): Lifecycle[IO, BufferedReader] =
      Lifecycle.make(
        acquire = IO { new BufferedReader(new FileReader(file)) }
      )(release = reader => IO { reader.close() })

    Using inheritance from Lifecycle.Basic:

    final class BufferedReaderResource(
      file: File
    ) extends Lifecycle.Basic[IO, BufferedReader] {
      def acquire: IO[BufferedReader] = IO { new BufferedReader(new FileReader(file)) }
      def release(reader: BufferedReader): IO[BufferedReader] = IO { reader.close() }
    }

    Using constructor-based inheritance from Lifecycle.Make, Lifecycle.LiftF, etc:

    final class BufferedReaderResource(
      file: File
    ) extends Lifecycle.Make[IO, BufferedReader](
      acquire = IO { new BufferedReader(new FileReader(file)) },
      release = reader => IO { reader.close() },
    )

    Or by converting from an existing cats.effect.Resource, scoped zio.ZIO or a zio.managed.ZManaged:

    Usage is done via use:

    open(file1).use {
      reader1 =>
        open(file2).use {
          reader2 =>
            readFiles(reader1, reader2)
        }
    }

    Lifecycles can be combined into larger Lifecycles via Lifecycle#flatMap (and the associated for-comprehension syntax):

    val res: Lifecycle[IO, (BufferedReader, BufferedReader)] = {
      for {
        reader1 <- open(file1)
        reader2 <- open(file2)
      } yield (reader1, reader2)
    }

    Nested resources are released in reverse order of acquisition. Outer resources are released even if an inner use or release fails.

    Lifecycle can be used without an effect-type with Lifecycle.Simple it can also mimic Java's initialization-after-construction with Lifecycle.Mutable

    Use Lifecycle's to specify lifecycles of objects injected into the object graph.

    import distage.{Lifecycle, ModuleDef, Injector}
    import cats.effect.IO
    
    class DBConnection
    class MessageQueueConnection
    
    val dbResource = Lifecycle.make(IO { println("Connecting to DB!"); new DBConnection })(_ => IO(println("Disconnecting DB")))
    val mqResource = Lifecycle.make(IO { println("Connecting to Message Queue!"); new MessageQueueConnection })(_ => IO(println("Disconnecting Message Queue")))
    
    class MyApp(db: DBConnection, mq: MessageQueueConnection) {
      val run = IO(println("Hello World!"))
    }
    
    val module = new ModuleDef {
      make[DBConnection].fromResource(dbResource)
      make[MessageQueueConnection].fromResource(mqResource)
      make[MyApp]
    }
    
    Injector[IO]()
      .produceGet[MyApp](module)
      .use(_.run())
      .unsafeRunSync()

    Will produce the following output:

    Connecting to DB!
    Connecting to Message Queue!
    Hello World!
    Disconnecting Message Queue
    Disconnecting DB

    The lifecycle of the entire object graph is itself expressed with Lifecycle, you can control it by controlling the scope of .use or by manually invoking Lifecycle#acquire and Lifecycle#release.

    Inheritance helpers

    The following helpers allow defining Lifecycle sub-classes using expression-like syntax:

    The main reason to employ them is to workaround a limitation in Scala 2's eta-expansion — when converting a method to a function value, Scala always tries to fulfill implicit parameters eagerly instead of making them parameters of the function value, this limitation makes it harder to inject implicits using distage.

    However, when using distage's type-based syntax: make[A].fromResource[A.Resource[F]] — this limitation does not apply and implicits inject successfully.

    So to workaround the limitation you can convert an expression based resource-constructor such as:

    import distage.Lifecycle, cats.Monad
    
    class A
    object A {
      def resource[F[_]](implicit F: Monad[F]): Lifecycle[F, A] = Lifecycle.pure(new A)
    }

    Into a class-based form:

    import distage.Lifecycle, cats.Monad
    
    class A
    object A {
      final class Resource[F[_]](implicit F: Monad[F])
        extends Lifecycle.Of(
          Lifecycle.pure(new A)
        )
    }

    And inject successfully using make[A].fromResource[A.Resource[F]] syntax of izumi.distage.model.definition.dsl.ModuleDefDSL.

    The following helpers ease defining Lifecycle subclasses using traditional inheritance where acquire/release parts are defined as methods:

    See also

    Lifecycle.SyntaxUse.use - main entrypoint

    ModuleDef.fromResource

    cats.effect.Resource

    zio.managed.ZManaged

    scoped zio.ZIO

    zio.ZLayer

  2. type Lifecycle2[+F[+_, +_], +E, +A] = Lifecycle[[β$0$]F[E, β$0$], A]
  3. type Lifecycle3[+F[-_, +_, +_], -R, +E, +A] = Lifecycle[[γ$1$]F[R, E, γ$1$], A]
  4. final class LifecycleAggregator[F[+_, +_], E] extends AnyRef

Value Members

  1. object Lifecycle extends LifecycleInstances
  2. object LifecycleAggregator

Inherited from AnyRef

Inherited from Any

Ungrouped