Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Sep 05 2019 14:43
    @typelevel-bot banned @jdegoes
  • Jan 31 2019 21:17
    codecov-io commented #484
  • Jan 31 2019 21:08
    scala-steward opened #484
  • Jan 31 2019 18:19
    andywhite37 commented #189
  • Jan 31 2019 02:41
    kamilongus starred typelevel/cats-effect
  • Jan 30 2019 00:01
    codecov-io commented #483
  • Jan 29 2019 23:51
    deniszjukow opened #483
  • Jan 29 2019 23:37
  • Jan 29 2019 23:22
  • Jan 29 2019 20:26
    Rui-L starred typelevel/cats-effect
  • Jan 29 2019 18:01
    jdegoes commented #480
  • Jan 29 2019 17:04
    thomaav starred typelevel/cats-effect
  • Jan 28 2019 17:43
    asachdeva starred typelevel/cats-effect
  • Jan 28 2019 07:12
    alexandru commented #480
  • Jan 28 2019 05:45
    codecov-io commented #482
  • Jan 28 2019 05:35
    daron666 opened #482
  • Jan 27 2019 13:56
    codecov-io commented #481
  • Jan 27 2019 13:46
    lrodero opened #481
  • Jan 27 2019 05:47
    codecov-io commented #460
  • Jan 27 2019 05:37
    codecov-io commented #460
Fabio Labella
@SystemFw
you can actually see why the behaviour your seek is impossible as soon as you have things that don't return Unit
def ints: IO[Int] = 3.pure[IO].handleErrorWith(e => 4.pure[IO])
  // this is handleError
def string: IO[String] = (ints <* boom).map(_.toString) 
  // if handleErrorWith worked here you'd try to return an Int instead of a String
if handleErrorWith installed a handler which is valid for all IOs flatMapped after this, which type should it return?
it can only be IO[Nothing], which can only be something that never terminates (IO cannot emit zero values)
Arnau Abella
@monadplus
Makes sense, the signature also gives some hints avoit it
Fabio Labella
@SystemFw
the behaviour which is closest to what you seek is the release action in Stream or Resource
Arnau Abella
@monadplus
I'll have a look at them tomorrow
Then, what is the purpose of handleErrorWith ?
Running a piece of code that is suspicious of throwing errors ?
Fabio Labella
@SystemFw
handling the errors of the current IO
it's the equivalent of catch
e.g. imagine wanting to return different http responses on success or failure of an operation
or perhaps wanting to retry something when there's an error
like, I don't see why this model is confusing
you have
IO.unit.handleError(...) >> boom, which doesn't handle errors in boom
just like
try {
  thing
} catch {
   ...
}

boom
doesn't handle errors in boom
Arnau Abella
@monadplus
It's not confusing now at all
Fabio Labella
@SystemFw
ah, nice ;)
Arnau Abella
@monadplus
but I couldn't understand it the first time :S
so thanks
Fabio Labella
@SystemFw
heh, that's ok
Arnau Abella
@monadplus
How do you handle situation where you fork then cancelled (e.g. the resource is not available) but there is a join afterwards ?
Fabio Labella
@SystemFw
you are going to have to be a bit more specific
that use of the word "cancelled" doesn't necessarily map to what I would think in the context of a fork
i.e. it's unclear if you are talking about some logical notion of "I don't want to do this anymore", or actual fiber interruption
Arnau Abella
@monadplus
Fiber interruption (e.g. Fiber.cancel)
I mean I dont want to do that anymore as .cancel
Fabio Labella
@SystemFw
who cancels? the thing that would do the join otherwise or something else?
Arnau Abella
@monadplus
The thread you forked from with .start
Fabio Labella
@SystemFw
and who joins?
I think it would be better if you could sketch an actual example. This can be tricky so it's easier that way
Arnau Abella
@monadplus
  (for {
    fiber <- readFile(new File("data/lore.txt")).start
    _     <- IO.sleep(100.millis) *> fiber.cancel
    lore  <- fiber.join // blocks
  } yield lore).map { println(_) }.unsafeRunSync()
@SystemFw
Fabio Labella
@SystemFw
well, that's kinda contrived given that this specific control flow doesn't really make a lot of sense, you alwasy join after cancel has happened
there are three things I'd say
if you just want to put a timeout on something
you should just readFile.timeout(5.seconds) (assuming that your readfile implementation is cancelable)
number 2 would be to only call .join if you haven't called cancel. In the simplest case this is an if, in more complicated cases you might need some coordination between the interrupter and the joiner
number 3 would be to put the result in a Ref + Deferred thing (in this case a simple Deferred), which has some form of default, this simplest case of which would be Deferred[Option[Thing]]
then you need to bracketCase or guaranteeCase the started operation so that it puts None on that Deferred when it gets cancelled
thoughts?
Arnau Abella
@monadplus
All three points are clear
nothing to add
John A. De Goes
@jdegoes
@monadplus Instead of fiber.join, call fiber.await. Join says, "the outcome of the fiber will be my outcome", await says, "just let me know what happened".
Arnau Abella
@monadplus
1.5.0 cats.effect.fiber does only expose cancel and join
Fabio Labella
@SystemFw
a quickly sketched prototype might look like this (requires testing ofc)
def await[F[_]: Concurrent, A](fa: F[A]): F[(F[Option[Either[Throwable, A]]], F[Unit])] =
  Deferred[F, Option[Either[Throwable, A]]].flatMap { result =>
       val action = {
          fa.attempt.flatMap(r => result.complete(r.some).uncancelable)
       }.guaranteeCase {
          case ExitCase.Canceled => result.complete(None)
          case _ => ().pure[F]
      }

      action.start.bracketCase(fiber => result.get.pure[F] -> fiber.cancel){
         case (fiber, ExitCase.Canceled) => fiber.cancel
         case (_, _) => ().pure[F]
      }
    }
obviously with a proper datatype instead of that monstrosity, and after testing (this isn't really the sort of code you want to sketch on gitter in 5 mins)
John A. De Goes
@jdegoes
@monadplus I sketched it in the design for Cats Effect 2.0. Until then you can get it in ZIO or with a patch like the above ^^^