Ref is an asynchronous, concurrent mutable reference. It provides safe concurrent access and modification of its content. You could consider Ref a purely functional wrapper over an AtomicReference in context F, that is always initialised to a value A.

Constructing a Ref

There are several ways to construct a Ref, the easiest the of factory method. Since the allocation of mutable state is not referentially transparent this side-effect is contained within F.

import arrow.fx.*

val ioRef: IO<Ref<ForIO, Int>> = Ref(IO.monadDefer(), 1).fix()

In case you want the side-effect to execute immediately and return the Ref instance you can use the unsafe function.

val unsafe: Ref<ForIO, Int> = Ref.unsafe(1, IO.monadDefer())

As you can see above this fixed Ref to the type Int and initialised it with the value 1.

In the case you want to create a Ref for F but not fix the value type yet you can use the Ref constructor. This returns an interface RefFactory with a single method later to construct an actual Ref.

val ref: RefFactory<ForIO> = Ref.factory(IO.monadDefer())

val ref1: IO<Ref<ForIO, String>> = ref.just("Hello, World!").fix()
val ref2: IO<Ref<ForIO, Int>> = ref.just(2).fix()

Working with Ref

Most operators found on AtomicReference can also be found on Ref within the context of F.

ioRef.flatMap { ref ->
// 1

ioRef.flatMap { ref ->
  ref.updateAndGet { it + 1 }
// 2

import arrow.core.toT

ioRef.flatMap { ref ->
  ref.getAndSet(5).flatMap { old ->
    ref.get().map { new -> old toT new }
// Tuple2(a=1, b=5)