//arrow-fx-stm/arrow.fx.stm/TVar

TVar

common class TVar<A>

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](index.html)'s before locking the [TVar](index.html)'s that have been written to and then checking only the [TVar](index.html)'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](index.html)'s small.




Another important thing to remember is that only writes will ever lock a [TVar](index.html) 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

Name Summary
Companion common object Companion

Functions

Name Summary
equals common open operator override fun equals(other: Any?): Boolean
hashCode common open override fun hashCode(): Int
unsafeRead common 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.

Do you like Arrow?

Arrow Org
<