Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
  • 00:38

    SethTisue on 2.11.x

    2.11: advance project SHAs (#13… (compare)

  • 00:38
    SethTisue closed #1346
  • 00:31
    SethTisue synchronize #1346
  • 00:24
    SethTisue edited #1346
  • 00:23
    SethTisue edited #1346
  • Jan 26 23:35
    kynthus commented #12322
  • Jan 26 23:23
    SethTisue commented #9456
  • Jan 26 23:04
    dwijnand commented #9456
  • Jan 26 22:50
    dongxuwang opened #1910
  • Jan 26 22:23
    SethTisue synchronize #1345
  • Jan 26 22:16

    dependabot-preview[bot] on bundler

    (compare)

  • Jan 26 22:16
    dependabot-preview[bot] commented #1887
  • Jan 26 22:16
    SethTisue closed #1887
  • Jan 26 22:16
    SethTisue commented #1887
  • Jan 26 22:15
    SethTisue commented #1909
  • Jan 26 22:09
    SethTisue converted_to_draft #1909
  • Jan 26 22:09
    SethTisue edited #1909
  • Jan 26 22:09
    SethTisue review_requested #1208
  • Jan 26 22:08
    SethTisue edited #1909
  • Jan 26 22:08
    SethTisue edited #1208
Fabio Labella
@SystemFw

cancelling, here, ends up meaning to just not poll any more

@joshlemer I don't think that says the whole story, let me expand, because I feels like this is similar to how cats-effect (or Monix) work

Josh
@joshlemer
although I wonder if this means they are not stack-safe...
Fabio Labella
@SystemFw

@joshlelemer
basically the way IO works is by constructing a datatype, which contains all the info to then interpret the IO (e.g. the constructor for side effecting code takes an => A, the constructor for flatMap takes IO[A] and A => IO[B], and they get stored in cases of an ADT). This datatype is then interpreted by the runloop once you unsafeRunSync at the end of world (typically the top of the call chain, in main).


The way the interpreter works is basically a while loop over two vars, the current IO[Any], and a Stack[Any => IO[Any]], you get the current, dispatch on its constructors and do what you need to do (e.g. evaluate the => A) and keep going with the next. This is a powerful approach because manipulating the stack allows you to implement complex features (e.g. you can shift to a trampoline every n calls to solve the stack safety problem you would otherwise have). It's also similar to what you mean by "polling": if you don't fetch the next thing off the stop, things just stop executing.


However, the crucial detail is that this by itself is not Interruption, it's suspension: i.e. you have defined a mechanism for an IO to suspend itself and give control back to the main thread (which is how fiber level concurrency is implemented), but interruption means that another IO needs to stop you.
So you need to have a shared (volatile, at the very least) variable which is the interrupt flag, the other IO sets it when it wants to interrupt you, and in your runloop you need to check this variable, and only then suspend yourself when the variable is true.


And that indeed brings up back to the initial question: how often do you check it? And there are different choices: you can check it at every flatMap, that's very fine grained but also quite expensive. The current choice in IO is to check it at every async boundary. And as I said, there's another whole bunch of complexity (in library code, not user code) to make sure things are resource safe and finalisers are registered and run correctly, in all scenarios

RoelofWobben
@RoelofWobben
How do I refractor the whole flatMap thing here :
sealed trait Expression{

  def eval: Sum[String, Double] = this match {

    case Addition(left, right) => left.eval flatMap { x => right.eval flatMap(y => Success(x + y))}
    case  Subtraction(left, right) => left.eval flatMap { x => right.eval flatMap(y => Success(x - y))}
}
Gavin Bisesi
@Daenyth
what monad is left/right/Success in?
RoelofWobben
@RoelofWobben
Sorry, monads are not explained yet. That will be in the cats book
RoelofWobben
@RoelofWobben
@Daenyth
Bastin Orar
@bastinOrar_twitter
I want a link to any beginner ML post with scala
Rob Norris
@tpolecat
@RoelofWobben assuming your result type acts like Either you can probably say for { x <- right.eval; y <- left.eval } yield x + y for example. That's probably where they are headed.
Gavin Bisesi
@Daenyth
@tpolecat I would have said that also except that he has a flatMap there on Success, so the yield is wrong
but that feels weird
@RoelofWobben what type are you calling flatMap on? Success is one of the members and left and right both have that type
Fabio Labella
@SystemFw
why do you find it weird?
Rob Norris
@tpolecat
I think that's like flatMap into pure … consider e.flatMap(a => Right(f(a))) which is e.map(f)
Fabio Labella
@SystemFw
yes
that's it
it's a map, so yield
Avremel Kaminetzky
@avremel
I have values in Future[Try[Option[Double]]] and Future[Option[Double]]. How can I add them? Should I be using Future.sequence?
RoelofWobben
@RoelofWobben
bad luck for me , yield is also not explained
Avremel Kaminetzky
@avremel
Or is there a way to use Future[Try[Option[Double]]] as Future[Option[Double]]?
RoelofWobben
@RoelofWobben
so there is no way I can refractor the this part out :
left.eval flatMap { x => right.eval flatMap(y
Gavin Bisesi
@Daenyth
@RoelofWobben
for {
  x <- left.eval
  y <- right.eval
} yield x + y
RoelofWobben
@RoelofWobben
oke, and I can put that into a function and call it
Fabio Labella
@SystemFw
I think the reason those things are not explained is that they are using the exercises to build the intuition you need to understand for/yield, once they do get there
RoelofWobben
@RoelofWobben
nope, in the other where I use it , it's x - y
so that code is not working
Fabio Labella
@SystemFw
it is
RoelofWobben
@RoelofWobben
@SystemFw for /yield is explained in the next chapter
Fabio Labella
@SystemFw
just pass an f: (Int, Int) => Int
and yield f(x, y)
exactly, so by doing this refactoring you are kinda "cheating"
RoelofWobben
@RoelofWobben
oke, then it let it be
I do not like cheating
Marcin Sokrates
@marcinsokrates_twitter
@avremel you should refactor to get rid of Future[Try[Option[Double]]] because it's redundant, Future.fromTry lets you skip the Try
RoelofWobben
@RoelofWobben
thanks all
time for the chapter about the for/yield and Option
Avremel Kaminetzky
@avremel
@marcinsokrates_twitter interesting. I was using toOption.flatten to remove the Try
  private def calculateShippingPriceRedo(cookie: String, country: Option[String], state: Option[String], shippingMethodId: Option[Int] = None): Future[Option[Double]] = {
    val countryWithDefault = country.getOrElse("US")

    shippingOptionsFull(cookie, country=countryWithDefault, state).map{ opt => opt.map{ rows =>
      shippingMethodId.flatMap{ id =>
          rows.find(_.shippingSpeedType === id ).orElse(rows.headOption).map(_.charge)
        }
      }.toOption.flatten
    }
  }
Derek Wickern
@dwickern
it depends what you want
Avremel Kaminetzky
@avremel
How would I use Future.fromTry?
Derek Wickern
@dwickern
do you want a successful future with None when the Try fails
Rob Norris
@tpolecat
Future[Try is usually wrong because Future already has the bulletproof behavior.
Derek Wickern
@dwickern
or a failed future
Avremel Kaminetzky
@avremel
Ye, it's someone's code, i don't want to refactor his code yet
Rob Norris
@tpolecat
So fto.flatMap(Future.fromTry) should give you Future[Option[Double]]
Avremel Kaminetzky
@avremel
Oh, thanks for that
And OptionT to add Future[Option[Double]], right?
Rob Norris
@tpolecat
You have two of those and want to add the doubles together?
Avremel Kaminetzky
@avremel
Yes
Rob Norris
@tpolecat
Yeah OptionT or Nested if you're using cats.