This prints out the unchanged value of 5
:
import zio.stm._
import zio.Console
import zio.Runtime.{default => rt}
class TInt(n: TRef[Int]):
def ++(): USTM[Unit] = n.update(_ + 1)
override def toString: String = n.toString
object TInt:
def make(n: Int): USTM[TInt] = TRef.make(n).map(TInt(_))
class Client:
val stmN: USTM[TInt] = TInt.make(5)
def increment: USTM[Unit] = stmN.flatMap(_.++())
val c = Client()
rt.unsafeRun(for
_ <- c.increment.commit
n <- c.stmN.commit
_ <- Console.printLine(n)
yield ())
How can I (w/ minimal structural changes) get it to print out the incremented value instead? With some testing, I know that TInt
is solid. The issue, I suspect, has to do w/ Client.stmN
being a USTM
and not reflecting the underlying mutation.
Undressed stmN: STM[TInt]
and now it's simply n: Tint
and being tracked as a constructor parameter. This requires construction of the Client
to be pulled into, effectively, a TRef.map
:
import zio.stm._
import zio.Console
import zio.Runtime.{default => rt}
class TInt(n: TRef[Int]):
def ++(): USTM[Unit] = n.update(_ + 1)
override def toString: String = n.toString
object TInt:
def make(n: Int): USTM[TInt] = TRef.make(n).map(TInt(_))
class Client(val n: TInt):
def increment: USTM[Unit] = n.++()
object Client:
def apply(): USTM[Client] = TInt.make(5).map(new Client(_))
rt.unsafeRun(for
c <- Client().commit
_ <- c.increment.commit
_ <- Console.printLine(c.n)
yield ())
The effect of this is that c
is now part of the returning value w/in unsafeRun
. Seems like Client
needed to be wrapped w/ a USTM
in order for its mutability to be taken seriously. In general, it is best, I have found, to not spread transactions amongst various classes w/in composition trees. While it does make for a nice OO design, it makes it difficult to get the mutability desired. Instead, try to keep everything on the same class and just use stm.T
* as the state.