r/scala•
MoonlitPeak

[2.13][CE2] Why is Ref.unsafe unsafe?

Why is the creation of a Ref effectful? From the source code comment itself:

Like apply but returns the newly allocated ref directly instead of wrapping it in F.delay. This method is considered unsafe because it is not referentially transparent -- it allocates mutable state. Such usage is safe, as long as the class constructor is not accessible and the public one suspends creation in IO

Why does either Ref creation or one of its callsites up the stack need to be wrapped in an effect? Is there any example of this unsafe actually being an issue? Surely it allocates mutable state, but afaiu getting and setting this Ref are already effectful operations and should be safe.

I wrote these two tests that illustrate the difference that I found so far:

    val x = Ref.unsafe[IO, Int](0)
    val a = x.set(1)
    val b = x.get.map(_ == 0)
    a.unsafeRunSync()
    assert(b.unsafeRunSync()) // fails

    val x = Ref.of[IO, Int](0)
    val a = x.flatMap(_.set(1))
    val b = x.flatMap(_.get.map(_ == 0))
    a.unsafeRunSync()
    assert(b.unsafeRunSync()) // passes

So the updates to the safe ref are not observable between effect runs, while the updates to the unsafe ref are.

But isn't the point of an effectful execution to tolerate side effects?

Posted Apr 10, 2025, 9:41 AM UTC

156
Loading comments…