Skip to content

Commit

Permalink
Merge pull request #2901 from armanbilge/topic/ref-access
Browse files Browse the repository at this point in the history
Relax `Ref#access` semantics if set more than once
  • Loading branch information
armanbilge authored Jun 16, 2022
2 parents 96dca5f + 3e40f68 commit a7bb2ad
Show file tree
Hide file tree
Showing 2 changed files with 3 additions and 20 deletions.
9 changes: 3 additions & 6 deletions kernel/shared/src/main/scala/cats/effect/kernel/Ref.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import cats.syntax.all._

import scala.annotation.tailrec

import java.util.concurrent.atomic.{AtomicBoolean, AtomicReference}
import java.util.concurrent.atomic.AtomicReference

/**
* A thread-safe, concurrent mutable reference.
Expand Down Expand Up @@ -65,7 +65,7 @@ abstract class Ref[F[_], A] extends RefSource[F, A] with RefSink[F, A] {
* (in which case `false` is returned) if another concurrent call to `access` uses its setter
* first.
*
* Once it has noop'd or been used once, a setter never succeeds again.
* Once it has noop'd a setter will never succeed.
*
* Satisfies: `r.access.map(_._1) == r.get` `r.access.flatMap { case (v, setter) =>
* setter(f(v)) } == r.tryUpdate(f).map(_.isDefined)`
Expand Down Expand Up @@ -314,10 +314,7 @@ object Ref {
def access: F[(A, A => F[Boolean])] =
F.delay {
val snapshot = ar.get
val hasBeenCalled = new AtomicBoolean(false)
def setter =
(a: A) =>
F.delay(hasBeenCalled.compareAndSet(false, true) && ar.compareAndSet(snapshot, a))
def setter = (a: A) => F.delay(ar.compareAndSet(snapshot, a))
(snapshot, setter)
}

Expand Down
14 changes: 0 additions & 14 deletions tests/shared/src/test/scala/cats/effect/kernel/RefSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -93,20 +93,6 @@ class RefSpec extends BaseSpec { outer =>
op must completeAs(true)
}

"access - setter should fail if called twice" in ticked { implicit ticker =>
val op = for {
r <- Ref[IO].of(0)
valueAndSetter <- r.access
(value, setter) = valueAndSetter
cond1 <- setter(value + 1)
_ <- r.set(value)
cond2 <- setter(value + 1)
result <- r.get
} yield cond1 && !cond2 && result == 0

op must completeAs(true)
}

"tryUpdate - modification occurs successfully" in ticked { implicit ticker =>
val op = for {
r <- Ref[IO].of(0)
Expand Down

0 comments on commit a7bb2ad

Please sign in to comment.