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 14:43
    @typelevel-bot banned @jdegoes
  • Jan 31 21:17
    codecov-io commented #484
  • Jan 31 21:08
    scala-steward opened #484
  • Jan 31 18:19
    andywhite37 commented #189
  • Jan 31 02:41
    kamilongus starred typelevel/cats-effect
  • Jan 30 00:01
    codecov-io commented #483
  • Jan 29 23:51
    deniszjukow opened #483
  • Jan 29 23:37
  • Jan 29 23:22
  • Jan 29 20:26
    Rui-L starred typelevel/cats-effect
  • Jan 29 18:01
    jdegoes commented #480
  • Jan 29 17:04
    thomaav starred typelevel/cats-effect
  • Jan 28 17:43
    asachdeva starred typelevel/cats-effect
  • Jan 28 07:12
    alexandru commented #480
  • Jan 28 05:45
    codecov-io commented #482
  • Jan 28 05:35
    daron666 opened #482
  • Jan 27 13:56
    codecov-io commented #481
  • Jan 27 13:46
    lrodero opened #481
  • Jan 27 05:47
    codecov-io commented #460
  • Jan 27 05:37
    codecov-io commented #460
Loïc Girault
@lgirault
yeah there is def update(f: A => A): F[Unit]
Gavin Bisesi
@Daenyth
problem being that get+update is not atomic
Loïc Girault
@lgirault
and its a get an set atomic. my "trivial" definition would lose atomicity
Gavin Bisesi
@Daenyth
yeah
I realized that after I said it
Loïc Girault
@lgirault
^_^
yeah I was like "wow did I miss something" ?
Gavin Bisesi
@Daenyth
the race condition prone version is trivial :awesome:
Loïc Girault
@lgirault
ok, I'll sleep on this one
maybe that can make an interesting PR if it's doable
johnw
@johnw

I've implemented Effect for my newtype class MyTask[E](toTask: monix.Task[E]) I did this in the following way:

class MyTaskEffect(effect: Effect[Task]) extends Effect[MyTask] { 
   /* implement the 9 methods that are uimplemented*/  
   override def runAsync[A](fa: MyTask[A])(cb: Either[Throwable, A] => IO[Unit]): IO[Unit] =
    effect.runAsync(fa.task)(cb)
//...
}

You instantiate an instance of the newtype like this:

 def create[C](
      initial: C
  )(implicit TaskEffect: Effect[Task], MyTaskEffect: Effect[MyTask]): MyTask[MyTaskEffectWithContext[C]] =
    Ref[MyTask, C](initial)(MyTaskEffect).map { initialRef =>
      new MyTaskEffectWithContext[C](TaskEffect, initialRef)
    }

Is there a better option?

Gavin Bisesi
@Daenyth
/shrug
check the laws
if it's good, it's good
johnw
@johnw
It seems to be lawful. I wasn't sure if there was some magic way of doing this sort of thing.
Fabio Labella
@SystemFw
@lgirault not doable
you can either make a version that risks a stale update
or one that repeats an effect a non-deterministic amount of times
but can't make a general one that works
in many cases, you can change your design/logic to not require that (e.g. by introducing a Deferredto avoid duplicating work), or you can use a Semaphore as a lock, so that you're free to do whatever you want in the critical section
Gavin Bisesi
@Daenyth
might even be something you could do with Signal or something depending on application logic needs
Fabio Labella
@SystemFw
but the general A => F[A] can't be done
we already tried a long time ago :P
(you can have one of the two versions above in your own code, for example when the effect is idempotent, but it's too risky to be in the public api imho)
Ross A. Baker
@rossabaker
I wanted that A => F[A] on Ref while working on an idle timeout yesterday, and came to the same conclusion. I ended up back on an imperative solution, but I want to revisit it. I think @ChristopherDavenport might find it useful as ember matures.
The desire being a timeout that can be "reset" by cancelling the current sleep and starting over before it fires.
Christopher Davenport
@ChristopherDavenport
You mean a locked ref?
Should be able to get something capable of it with a Semaphore. However you need to bar any modification options until F[A] returns.
Its definitely not something that generally should see much use.
Ross A. Baker
@rossabaker
Something vaguely like this:
trait Alarm[F] {
  // Sets the alarm `d` into the future
  // Cancels the last reset
  def reset(d: Duration): F[Unit]
  // completes `d` after `reset`
  def buzz: F[Unit]
  // Cancels the last reset. `buzz` will never complete.
  def cancel: F[Unit]
}
I wanted a Ref of a Fiber, but that wasn't quite right.
I can imagine ember using something similar to that for an idle timeout: race against buzz, and reset on reads and writes.
Fabio Labella
@SystemFw

The desire being a timeout that can be "reset" by cancelling the current sleep and starting over before it fires.

Mmm, can you give a bit more info? I've implemented similar logic a few times

well, I guess the interface is informative enough
I'm curious about why you would have buzz never complete as opposed as failed
Christopher Davenport
@ChristopherDavenport
If its racing something else, never completing means the other thing wins.
Which is the general use case of buzz there.
Fabio Labella
@SystemFw
I see
Christopher Davenport
@ChristopherDavenport
The above I would use for something like an idle timeout on a body.
Fabio Labella
@SystemFw
@rossabaker do you have any tests (in any form, snippets with expected results would be fine) for Alarm?
Fabio Labella
@SystemFw
I think I have an implementation, but need tests
what do you want to happen if you call buzz before any reset?
Fabio Labella
@SystemFw
I'm going with "never completes"
anyway, let me know tomorrow and I can raise a PR to http4s I think
(assuming this works)
Ross A. Baker
@rossabaker
The place I needed it is blaze, and it's an awkward fit because futures and units. I think it would be useful in ember, which probably has a similar need, but can stand the effectful contexts.
Fabio Labella
@SystemFw
I see
this is the untested version I have
/**
  * Resettable timeout
  */
trait Alarm[F[_]] {
  /**
    * Sets the alarm `d` into the future
    * Cancels the last reset
    */
  def reset(d: FiniteDuration): F[Unit]

  /**
    *  Completes `d` after `reset`. Never completes if called before `reset`
    *  The purpose of `buzz` is to be raced with something else.
    */
  def buzz: F[Unit]

  /**
    * Cancels the last reset. `buzz` will never complete.
    */
  def cancel: F[Unit]
}
object Alarm {
  def create[F[_]](implicit F: Concurrent[F], timer: Timer[F]): F[Alarm[F]] =
    for {
      empty <- Deferred[F, Fiber[F, Unit]]
      state <- Ref[F].of(empty)
      fb <- F.never[Unit].start
      _ <- empty.complete(fb)
    } yield new Alarm[F] {

      def reset(d: FiniteDuration): F[Unit] = for {
        newFiber <- Deferred[F, Fiber[F, Unit]]
        oldFiber <- state.getAndSet(newFiber)
        _ <- oldFiber.get.flatMap(_.cancel)
        fiber <- timer.sleep(d).start
        _ <- newFiber.complete(fiber)
      } yield ()

      def buzz: F[Unit] = for {
        d <- state.get
        fb <- d.get
        _ <- fb.join
      } yield ()

      def cancel: F[Unit] = for {
        d <- state.get
        fb <- d.get
        _ <- fb.cancel
      } yield ()
    }
}
Ross A. Baker
@rossabaker
Oh, clever.