TVar

class TVar<A>(source)

A TVar is a mutable reference that can only be (safely) accessed inside a STM transaction.

Creating a TVar

There are two ways of creating TVar's:

Strictly speaking TVar.new is not necessary as it can be defined as atomically { newTVar(v) } however TVar.new is much faster because it avoids creating a (pointless) transaction. STM.newTVar should be used inside transactions because it is not possible to use TVar.new inside STM due to suspend.

Reading a value from a TVar

One-off reading from a TVar outside of a transaction can be done by using TVar.unsafeRead. Despite the name using this method is only unsafe if the read value (or a derivative) is then used inside another transaction which may cause race conditions again. However the benefit of using this over atomically { tvar.read() } is that it avoids creating a transaction and is thus much faster.

import arrow.fx.stm.TVar

suspend fun main() {
//sampleStart
val tvar = TVar.new(10)
val result = tvar.unsafeRead()
//sampleEnd
println(result)
}

Reading from a TVar inside a transaction is done by using STM.read.

import arrow.fx.stm.TVar
import arrow.fx.stm.atomically

suspend fun main() {
//sampleStart
val tvar = TVar.new(10)
val result = atomically {
tvar.read()
}
//sampleEnd
println(result)
}

Checking the validity of a transaction is done by checking the contents of all accessed TVar's before locking the TVar's that have been written to and then checking only the TVar's that have only been read not modified again. To keep transactions as fast as possible it is key to keep the number of accessed TVar's small.

Another important thing to remember is that only writes will ever lock a TVar and only those that need to be changed. This means that so long as transactions access disjoint sets of variables or a transaction is read only, they may run in parallel.

Modifying the value inside the TVar

Writing a new value to the TVar:

import arrow.fx.stm.TVar
import arrow.fx.stm.atomically

suspend fun main() {
//sampleStart
val tvar = TVar.new(10)
val result = atomically {
tvar.write(20)
}
//sampleEnd
println(result)
}

Modifying the value based on the initial value:

import arrow.fx.stm.TVar
import arrow.fx.stm.atomically

suspend fun main() {
//sampleStart
val tvar = TVar.new(10)
val result = atomically {
tvar.modify { it * 2 }
}
//sampleEnd
println(result)
}

Writing a new value to the TVar and returning the initial value:

import arrow.fx.stm.TVar
import arrow.fx.stm.atomically

suspend fun main() {
//sampleStart
val tvar = TVar.new(10)
val result = atomically {
tvar.swap(20)
}
//sampleEnd
println("Result $result")
println("New value ${tvar.unsafeRead()}")
}

Types

Link copied to clipboard
object Companion

Functions

Link copied to clipboard
open operator override fun equals(other: Any?): Boolean
Link copied to clipboard
open override fun hashCode(): Int
Link copied to clipboard
suspend fun unsafeRead(): A

Read the value of a TVar. This has no consistency guarantees for subsequent reads and writes since it is outside of a stm transaction.