Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
  • 23:43
    saraiva132 commented #2683
  • 23:37
    saraiva132 edited #2681
  • 23:34
    saraiva132 commented #2681
  • 23:31
    saraiva132 edited #2681
  • 23:30
    saraiva132 synchronize #2681
  • 23:23
    hmemcpy commented #2687
  • 23:22
    hmemcpy commented #2687
  • 23:19
    hmemcpy commented #2687
  • 23:04
    neko-kai review_requested #2687
  • 23:04
    neko-kai review_requested #2687
  • 23:04
    neko-kai opened #2687
  • 22:46
    jdegoes commented #2671
  • 20:45
    ioleo commented #2671
  • 20:45
    adamgfraser commented #2671
  • 20:44
    ioleo commented #2671
  • 20:41
    ioleo commented #2671
  • 20:41
    ioleo commented #2686
  • 20:40
    ioleo commented #2686
  • 20:27
    adamgfraser commented #2666
  • 20:27
    adamgfraser commented #2685
Yann Simon
@yanns
@psisoyev I think I had the same kind of issues as you're having. Thinking of "dependency injection" does not really work. At the end, each function is total, and each layer must have all dependencies, even though they are needed by a sub-layer. I don't find this very beautiful.
Adam Fraser
@adamgfraser
@tampler You need to provide the Live environment. By default effects in ZIO Test use test implementations of the standard environment types that allow you to adjust the clock and print to a buffer that you can introspect. In your example, import zio.test.environment.Live and then do Live.live(Party.party).
Boris V.Kuznetsov
@tampler
@adamgfraser Thanks, that worked ! I'll commit your fix
Adam Fraser
@adamgfraser
:thumbsup:
Pavels Sisojevs
@psisoyev
@yanns exactly what I thought - it’s not beautiful. That’s why I thought I’m doing something wrong and was trying to change it, but couldn’t find a better way
Adam Fraser
@adamgfraser
You can create a trait that just bundled up all the dependencies.
Pavels Sisojevs
@psisoyev

You can create a trait that just bundled up all the dependencies.

but then I can just use type alias which will have all the dependencies and just use it everywhere instead of specific types. and then the hell will come with testing this - i will need to provide the whole thing all the time

Yann Simon
@yanns
@psisoyev I don't have so much experience so take my words with a grain of salt.
Idea: it may also be possible to have several environments to bound ZIO components.
The "deeper" environment would hide the dependencies so that the "deeper" components can be used in higher ones
Pavels Sisojevs
@psisoyev
@yanns the problem for me is that whenever I have MyService, which uses Logger, it shouldn’t know in its environment what kind of logger implementation im using (is it ConsoleLogger or VoidLogger shouldn’t matter and affect R of MyService)
Adam Fraser
@adamgfraser
So why not just parameterize it on the logger?
Pavels Sisojevs
@psisoyev

yeah, one of the options is to do something like:

trait ConsoleLogger extends MyLogger {
    val console: Console

    override val logger: Service = new Service {
      override def info(message: String): ZIO[Any, Nothing, Unit] = console.console.putStrLn(message)
    }
  }

but then it looks like a cake pattern a bit (is it a problem?) and it could possible to have naming clashes (still manageable)

Pavels Sisojevs
@psisoyev
after revisiting http://degoes.net/articles/zio-environment once again, it seems that initially I understood the concept correctly, but wanted to get a bit too much from it. however, it seems that creating type aliases for these “deep local environments” is still not that bad
Adam Fraser
@adamgfraser
:+1:
Pavels Sisojevs
@psisoyev
also, self typing is also making it a bit better:
https://scastie.scala-lang.org/SJz9EI9NSGepXAb9QUqNzg
John A. De Goes
@jdegoes
@psisoyev That's the most straightforward way to do service-to-service dependency. It works, it's very object-oriented, of course, but I don't think that's necessarily a problem.
Pavels Sisojevs
@psisoyev

@psisoyev That's the most straightforward way to do service-to-service dependency. It works, it's very object-oriented, of course, but I don't think that's necessarily a problem.

it feels OO, indeed. what would be the most advanced super functional turbo 2077 way of doing this? :)
having MyService aware of internal implementation details of Logger (MyService with Logger with Console as R in MyService helper package object ) or there is a better way?

Pavels Sisojevs
@psisoyev

I have simplified my example to expand my question. I have removed self typing and now there is another problem - I have to provide both implementations even though I want to use only one of it:

https://scastie.scala-lang.org/TRf6YEteSZ6iixrjl2HhVw

so for example I want to use only ConsoleLogger but this approach forces me to have FileWriter in my R

of course with self typing its not the case:
https://scastie.scala-lang.org/jahshaJQTXOLL6ZZRxy4nA

im not a big fan of self typing, but looking for ways to do it in a better way

so far I’ve came up with this:
https://scastie.scala-lang.org/uXVuAER3TZaJjjtw7ATHsA
is this the idiomatic way of using environment?

Kai
@neko-kai

@psisoyev
It doesn’t look like it goes all the way, as in MyService.Live you’re pinning not just MyService implementation, but also MyLogger’s implementation to concrete ConsoleLogger – the layers leak into each other.

The most advanced turbo-functional way is using FunctorK (https://typelevel.org/cats-tagless/) to write implementations against concrete R – that way you can actually make use of the syntax proxies that make ZIO env feel ‘functional’ inside modules’ implementations – and then mapping them with FunctorK instance that uses .provide back to Any(MyService[MyLogger] => MyService[Any]) – that way you hide the dependencies again and let other modules depend on MyService[Any] and use syntax. Circular dependencies may require using lazy vals inside the env trait.

However, no one does it that way yet, so you’ll have to figure out some parts of how to make it all fit yourself :)

Pavels Sisojevs
@psisoyev
@neko-kai great! It seems this is exactly what I was looking for. I will take a look, thank you
Dennis
@dennis4b_twitter
Is there a way to find out which effects are taking up the most time? I must have some code somewhere which should be wrapped in blocking or which takes too much time and is starving my app sometimes. Incidentally, if I would have a some threadpool for long running tasks and lock an effect onto it, what happens if it calls any blocking code, ie will it still get shifted to the blocking pool or is it really locked on the worker pool?
John A. De Goes
@jdegoes
@psisoyev Kai's suggestion should be investigated, also there are several other ways: represent graph edges as ZIO[Dependee, Nothing, Depender] (note classic arrow programming is painful and you may want to change to use Shapeless or something like it to manage dependencies); make polymorphic modules (I don't recommend but it solves the problem); higher-kinded environments (if you go the tagless-final route), etc. The simplest way that your team is going to be happy with is just expressing dependencies as an ordinary field, e.g. val console: Console.Service[Any] inside the implementation trait. This means business logic has one way of expressing dependencies (R) and service logic has another way (accessor-based dependency), which is less satisfying but works fairly well in practice.
@dennis4b_twitter We're going to do a LOT more work around that in the future. I have seen people write code to detect a wayward effect.
Kai
@neko-kai
@jdegoes I think FunctorK-mapping/R-contramapping modules and then wiring them up like normal values is the only way to achieve uniform use of R dependencies everywhere. Requires some machinery, but I’m definitely planning to investigate it...
John A. De Goes
@jdegoes
@neko-kai Contramapping = edges are ZIO effects that require and provide something. You use arrow composition to express graph. It's not convenient because either you end up with proxies (OOP) or tuples (FP). Type-level machinery would be necessary to make that really nice, an HSet (coproduct without duplicates).
Kai
@neko-kai

@jdegoes You immediately run into having to create a massive amount of intermediate traits (or yeah, juggling tuples). Arrows also impose ordering even when most of the components constructors are not order-sensitive. You could use type-level machinery, like cakeless, but e.g. distage is able to wire arbitrary R dependencies via contramapping right now:

https://scastie.scala-lang.org/0UUqMafrRb6LHNAJ0s1ODg

import cats.Contravariant
import distage._
import izumi.distage.model.providers.ProviderMagnet
import izumi.distage.constructors.TraitConstructor
import zio._

object App extends zio.App {
  trait Dependee[-R] {
    def x(y: String): URIO[R, Int]
  }
  trait Depender[-R] {
    def y: URIO[R, String]
  }
  implicit val contra1: Contravariant[Dependee] = new Contravariant[Dependee] {
    def contramap[A, B](fa: Dependee[A])(f: B => A): Dependee[B] = new Dependee[B] { def x(y: String) = fa.x(y).provideSome(f) }
  }
  implicit val contra2: Contravariant[Depender] = new Contravariant[Depender] {
    def contramap[A, B](fa: Depender[A])(f: B => A): Depender[B] = new Depender[B] { def y = fa.y.provideSome(f) }
  }

  trait DependeeR { def dependee: Dependee[Any] }
  trait DependerR { def depender: Depender[Any] }
  object dependee extends Dependee[DependeeR] { def x(y: String) = ZIO.accessM(_.dependee.x(y)) }
  object depender extends Depender[DependerR] { def y            = ZIO.accessM(_.depender.y) }

  def run(args: List[String]) = {
    // cycle
    object dependerImpl extends Depender[DependeeR] {
      def y: URIO[DependeeR, String] = dependee.x("hello").map(_.toString)
    }
    object dependeeImpl extends Dependee[DependerR] {
      def x(y: String): URIO[DependerR, Int] = if (y == "hello") UIO(5) else depender.y.map(y.length + _.length)
    }
    def fullfill[R: Tag: TraitConstructor, M[_]: TagK: Contravariant](m: M[R]): ProviderMagnet[M[Any]] = {
      TraitConstructor[R].provider.map(r => Contravariant[M].contramap(m)(_ => r))
    }

    val module = new ModuleDef {
      make[Depender[Any]].from(fullfill(dependerImpl))
      make[Dependee[Any]].from(fullfill(dependeeImpl))
    }

    Injector()
      .produceF[Task](module, GCMode.NoGC).use(_ run TraitConstructor[DependeeR].provider.map {
        (for {
          r <- dependee.x("zxc")
          _ <- Task(println(s"result: $r"))
        } yield ()).provide(_)
      }).fold(_ => 1, _ => 0)
  }
}

Note that this will keep working even if a module's constructor is not a plain function, but an effect or a Managed – there’s .fromEffect & .fromResource operators – effectful/managed constructors would usually bring the most pain as they immediately require intermediate traits and careful ordering, but distage removes all ordering, cycle & intermediate-trait concerns immediately.

gannicottb
@gannicottb
I'm wrapping a Java API library (AdWords API) for use in functional Scala project. One of the (many) things I'm unclear on is how to handle managing the initialization and usage of an API client object from the library in a functional way. Should it be provided in the Environment and accessed in the functions that need it? Is it ok to initialize one as a private val inside of a wrapper class (I'm guessing no, feels effectful). Should the wrapper class return itself as a ZIO of some type? Apologies if this is too many questions at once!
just noticed that we're trying to move to discord
John A. De Goes
@jdegoes
@neko-kai This is new!
Dejan Mijić
@mijicd
@/all today's hackathon starts at 6pm, at Tamara-Danz-Strasse 1 (The Hub @ Zalando). Looking forward to see you all there!
andrey
@andrey55980088_twitter
Hi, is it right place to ask about zio-kafka?
I just picked example from main page, but catch error in runtime - Exception in thread "main" zio.FiberFailure: Fiber failed.
An unchecked error was produced.
java.lang.NoSuchMethodError: zio.Schedule$.spaced(Lzio/duration/Duration;)Lzio/ZSchedule;
maybe someone can help me to fix
"org.typelevel" %% "cats-core" % "2.0.0",
"org.typelevel" %% "cats-effect" % "2.0.0",
"dev.zio" %% "zio-kafka" % "0.3.1",
"dev.zio" %% "zio" % "1.0.0-RC16",
"dev.zio" %% "zio-interop-cats" % "2.0.0.0-RC6",
that is my deps
that is code -
consumer
.subscribeAnd(Subscription.topics("games"))
.plainStream(Serde.int, Serde.string)
.map { record =>
println(record.record.value())
record.offset
}
.chunks
.mapM { chunk =>OffsetBatch(chunk.toSeq).commit}
.runDrain
sorry for inconvinience or flood
Dennis
@dennis4b_twitter
The latest zio-kafka for use with zio RC16 is 0.3.2, are you sure no older versions of any critical libraries are being pulled in through dependencies?
andrey
@andrey55980088_twitter
but 0.3.2 not in maven central yet...
I don't know what is critical and which versions are older or newer, there is a lot of cjanges each month:)
Dennis
@dennis4b_twitter
ah ok. Sbt should tell you if it is replacing library versions but I'm not sure how to ask for it exactly. But if it compiles and then gives this kind of error for me it's usually that some wrong version is included
andrey
@andrey55980088_twitter
yes, reverted zio to rc-15, seems working now
Dennis
@dennis4b_twitter
"evicted" was the word I was looking for :) great that it's working now
Abdhesh Kumar
@abdheshkumar

Hi, I am trying to understand the code of zio library and the code is from DefaultRuntime.scala.

package zio

import zio.clock.Clock
import zio.console.Console
import zio.system.System
import zio.random.Random
import zio.blocking.Blocking
import zio.internal.{ Platform, PlatformLive }

trait DefaultRuntime extends Runtime[ZEnv] {
  val Platform: Platform = PlatformLive.Default
  val Environment: ZEnv  = new Clock.Live with Console.Live with System.Live with Random.Live with Blocking.Live
}

IntelliJ showing ZEnv in red as an error but zio code compile. I don't understand how this code compiled?

I saw ZEnv is defined in ZEnvDefinition in a trait which is not extended by DefaultRuntime
reibitto
@reibitto
As for IntelliJ... yeah, it often shows things that aren't errors in red unfortunately
Abdhesh Kumar
@abdheshkumar
Thank you @reibitto.
Cyrille Chépélov
@cchepelov

Hi there,
using ZIO "cinderblock-style" here (as opposed to having a "single-pour monoZIO" monolith where there is only zero or one explicit unsafeRun at all, we have many islands of ZIO runs, choreographed together by a matrix of imperative or Future and/or Akka code).
Had to use a couple ZStream and ZQueue where the stream or queue is long-running, i.e. it is allocated at one point of time (e.g. a service constructor) and then used later, in a different ZIO island.

For now what we do is we have a service constructor that ends up initializing a bunch of private vals as

  private val (foo, bar, toto) = someZioRuntime.unsafeRun (for {  
    foo <- zuniverse.someFoo
    bar <-  zuniverse.someBar
    baz <-  zuniverse.someBaz
} yield (foo, bar, baz) )

It clearly sounds… Odd and ugly, especially as the someZioRuntimetypically ends up into an implicit parameter of that constructor.

Apart from switching to a monocrystalline zio architecture (not quite there yet!), does anyone have a better idea?

Kai
@neko-kai
@cchepelov Not many better ideas than to go full zio, unsafeRun is really dangerous and will lead to deadlocks when executed on the same thread pool as zio itself – the computation that calls unsafeRun should always be on a dedicated thread not mixed with zio’s threads. Mixing ZIO with Futures or cats IO is manageable, mixing ZIO with statements requires attention.
If some of your ZIO computations that you unsafeRun are totally synchronous you could replace ZIO there with cats SyncIO, monix Coeval or izumi MiniBIO – these types all have guaranteed synchronous execution, so they are safer to unsafeRun in mixed synchronous environment (still only as long as you’re on a dedicated thread)
Cyrille Chépélov
@cchepelov

@heko-kai the "calculation" in question is really just creating the ZStream or ZQueue. So I guess running that over cats' SyncIO doesn't really make sense, does it?

At this moment, going monolithic zio isn't going to be an option — one of our "matrices" (or "mortars" to keep the cinderblock analogy) is Play, another is akka-http, and there are a couple others for which there is no obvious reliable "pure zio" replacement available in the short term.

As it happens, indeed we never call .unsafeRun from a ZIO thread.
A typical control flow is, as I said, synchronous/DI creation of services→zioRuntime.unsafeRun(build things that return an IO[_, DesiredThing])
Another is (e.g.) HTTP→Akka HTTP Routing (futures in an Akka system's ExecutionContext)→zio.unsafeRunToFuture(zio calculation)→→HTTP