Pure holder of a single value of type A
that can be both read
and updated in the effect F
.
The update methods have the same semantics as Ref, as well as
propagating changes to discrete
(with a last-update-wins policy
in case of very fast updates).
The access
method differs slightly from Ref
in that the update
function, in the presence of discrete
, can return false
and
need looping even without any other writers.
Attributes
- Companion:
- object
- Source:
- Signal.scala
- Graph
- Supertypes
Members list
Value members
Inherited methods
Obtains a snapshot of the current value, and a setter for updating it.
Obtains a snapshot of the current value, and a setter for updating it.
The setter attempts to modify the contents from the snapshot to the new value (and return
true
). If it cannot do this (because the contents changed since taking the snapshot), the
setter is a noop and returns false
.
Satisfies: r.access.map(_._1) == r.get
and r.access.flatMap { case (v, setter) => setter(f(v)) } == r.tryUpdate(f).map(_.isDefined)
.
Attributes
Returns a signal derived from this one, that drops update events that did not change the value.
Returns a signal derived from this one, that drops update events that did not change the value.
Attributes
- Inherited from:
- Signal
- Source:
- Signal.scala
Returns a stream of the current value of the signal. An element is always available -- on each pull, the current value is supplied.
Returns a stream of the current value of the signal. An element is always available -- on each pull, the current value is supplied.
Attributes
- Inherited from:
- Signal
- Source:
- Signal.scala
Returns a stream of the current value and subsequent updates to this signal.
Returns a stream of the current value and subsequent updates to this signal.
Even if you are pulling as fast as possible, updates that are very close together may
result in only the last update appearing in the stream. In general, when you pull
from this stream you may be notified of only the latest update since your last pull.
If you want to be notified about every single update, use a Queue
or Channel
instead.
Attributes
- Inherited from:
- Signal
- Source:
- Signal.scala
Like modify but schedules resulting effect right after modification.
Like modify but schedules resulting effect right after modification.
Useful for implementing effectful transition of a state machine, in which an effect is performed based on current state and the state must be updated to reflect that this effect will be performed.
Both modification and finalizer are within a single uncancelable region, to prevent canceled finalizers from leaving the Ref's value permanently out of sync with effects actually performed. if you need cancellation mechanic in finalizer please see flatModifyFull.
Attributes
Like modify but schedules resulting effect right after modification.
Like modify but schedules resulting effect right after modification.
Unlike flatModify finalizer cancellation could be unmasked via supplied Poll
.
Modification itself is still uncancelable.
When used as part of a state machine, cancelable regions should usually have an onCancel
finalizer to update the state to reflect that the effect will not be performed.
Attributes
Like modifyState but schedules resulting effect right after state computation & update.
Like modifyState but schedules resulting effect right after state computation & update.
Both modification and finalizer are uncancelable, if you need cancellation mechanic in finalizer please see flatModifyStateFull.
Attributes
Like modifyState but schedules resulting effect right after modification.
Like modifyState but schedules resulting effect right after modification.
Unlike flatModifyState finalizer cancellation could be masked via supplied Poll[F]
.
Modification itself is still uncancelable.
Attributes
Gets the current value of this Signal
.
Returns the current value of this Signal
and a Stream
to subscribe to
subsequent updates, with the same semantics as discrete. The updates
stream should be compiled at most once.
Returns the current value of this Signal
and a Stream
to subscribe to
subsequent updates, with the same semantics as discrete. The updates
stream should be compiled at most once.
Attributes
- Inherited from:
- Signal
- Source:
- Signal.scala
Like tryModifyState but retries the modification until successful.
Like tryModifyState but retries the modification until successful.
Attributes
Like tryUpdate
but allows the update function to return an output value of type B
. The
returned action completes with None
if the value is not updated successfully and
Some(b)
otherwise.
Update the value of this Ref
with a state computation.
Attempts to modify the current value once, returning false
if another concurrent
modification completes between the time the variable is read and the time it is set.
Modifies the current value using the supplied update function. If another modification
occurs between the time the current value is read and subsequently updated, the
modification is retried using the new value. Hence, f
may be invoked multiple times.
Modifies the current value using the supplied update function. If another modification
occurs between the time the current value is read and subsequently updated, the
modification is retried using the new value. Hence, f
may be invoked multiple times.
Satisfies: r.update(_ => a) == r.set(a)
Attributes
Returns when the condition becomes true, semantically blocking in the meantime.
Returns when the condition becomes true, semantically blocking in the meantime.
This method is particularly useful to transform naive, recursive
polling algorithms on the content of a Signal
/ SignallingRef
into semantically blocking ones. For example, here's how to
encode a very simple cache with expiry, pay attention to the
definition of view
:
trait Refresh[F[_], A] {
def get: F[A]
}
object Refresh {
def create[F[_]: Temporal, A](
action: F[A],
refreshAfter: A => FiniteDuration,
defaultExpiry: FiniteDuration
): Resource[F, Refresh[F, A]] =
Resource
.eval(SignallingRef[F, Option[Either[Throwable, A]]](None))
.flatMap { state =>
def refresh: F[Unit] =
state.set(None) >> action.attempt.flatMap { res =>
val t = res.map(refreshAfter).getOrElse(defaultExpiry)
state.set(res.some) >> Temporal[F].sleep(t) >> refresh
}
def view = new Refresh[F, A] {
def get: F[A] = state.get.flatMap {
case Some(res) => Temporal[F].fromEither(res)
case None => state.waitUntil(_.isDefined) >> get
}
}
refresh.background.as(view)
}
}
Note that because Signal
prioritizes the latest update when
its state is updating very quickly, completion of the F[Unit]
might not trigger if the condition becomes true and then false
immediately after.
Therefore, natural use cases of waitUntil
tend to fall into
two categories:
- Scenarios where conditions don't change instantly, such as
periodic timed processes updating the
Signal
/SignallingRef
. - Scenarios where conditions might change instantly, but the
p
predicate is monotonic, i.e. if it tests true for an event, it will test true for the following events as well. Examples include waiting for a unique ID stored in aSignal
to change, or waiting for the value of theSignal
of an orderedStream[IO, Int]
to be greater than a certain number.
Attributes
- Inherited from:
- Signal
- Source:
- Signal.scala