Skip to content

Commit d509284

Browse files
pakoitonomisRev
authored andcommitted
Add new recommended constructor for Ref (arrow-kt#1436)
* Add new constructor for Ref * Update docs * detekt * Refactor Ref constructors * Refactor API for MVar * Add ref to MonadDefer and MVar to Concurrent * Fix Semaphore * Code review * Fix docs * Fix compilation * Fix docs * Fix ktlint * Fix tests * Fix tests * Fix dokka * Fix dokka
1 parent b3b24fa commit d509284

File tree

13 files changed

+81
-70
lines changed

13 files changed

+81
-70
lines changed

modules/docs/arrow-docs/docs/docs/effects/ref/README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Since the allocation of mutable state is not referentially transparent this side
2121
import arrow.effects.*
2222
import arrow.effects.extensions.io.monadDefer.monadDefer
2323
24-
val ioRef: IO<Ref<ForIO, Int>> = Ref.of(1, IO.monadDefer()).fix()
24+
val ioRef: IO<Ref<ForIO, Int>> = Ref(IO.monadDefer()) { 1 }.fix()
2525
```
2626

2727
In case you want the side-effect to execute immediately and return the `Ref` instance you can use the `unsafe` function.
@@ -33,13 +33,13 @@ val unsafe: Ref<ForIO, Int> = Ref.unsafe(1, IO.monadDefer())
3333
As you can see above this fixed `Ref` to the type `Int` and initialised it with the value `1`.
3434

3535
In the case you want to create a `Ref` for `F` but not fix the value type yet you can use the `Ref` constructor.
36-
This returns an interface `PartiallyAppliedRef` with a single method `of` to construct an actual `Ref`.
36+
This returns an interface `RefFactory` with a single method `delay` to construct an actual `Ref`.
3737

3838
```kotlin:ank:silent
39-
val ref: PartiallyAppliedRef<ForIO> = Ref(IO.monadDefer())
39+
val ref: RefFactory<ForIO> = Ref.factory(IO.monadDefer())
4040
41-
val ref1: IO<Ref<ForIO, String>> = ref.of("Hello, World!").fix()
42-
val ref2: IO<Ref<ForIO, Int>> = ref.of(2).fix()
41+
val ref1: IO<Ref<ForIO, String>> = ref.delay { "Hello, World!" }.fix()
42+
val ref2: IO<Ref<ForIO, Int>> = ref.delay { 2 }.fix()
4343
```
4444

4545
## Working with Ref

modules/effects/arrow-effects-data/src/main/kotlin/arrow/effects/MVar.kt

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ interface MVar<F, A> {
2626
*
2727
* fun main(args: Array<String>) {
2828
* //sampleStart
29-
* val mvar = MVar(IO.async())
29+
* val mvar = MVar.factoryUncancelable(IO.async())
3030
*
3131
* mvar.empty<Int>().flatMap { v ->
3232
* v.isEmpty()
3333
* }.unsafeRunSync() == true
3434
*
35-
* mvar.of(10).flatMap { v ->
35+
* mvar.just(10).flatMap { v ->
3636
* v.isEmpty()
3737
* }.unsafeRunSync() == false
3838
* //sampleEnd
@@ -51,9 +51,9 @@ interface MVar<F, A> {
5151
*
5252
* fun main(args: Array<String>) {
5353
* //sampleStart
54-
* val mvar = MVar(IO.async())
54+
* val mvar = MVar.factoryUncancelable(IO.async())
5555
*
56-
* mvar.of(10).flatMap { v ->
56+
* mvar.just(10).flatMap { v ->
5757
* v.isNotEmpty()
5858
* }.unsafeRunSync() == true
5959
*
@@ -77,7 +77,7 @@ interface MVar<F, A> {
7777
*
7878
* fun main(args: Array<String>) {
7979
* //sampleStart
80-
* val mvar = MVar(IO.async())
80+
* val mvar = MVar.factoryUncancelable(IO.async())
8181
*
8282
* mvar.empty<Int>().flatMap { v ->
8383
* v.put(5).flatMap {
@@ -101,13 +101,13 @@ interface MVar<F, A> {
101101
*
102102
* fun main(args: Array<String>) {
103103
* //sampleStart
104-
* val mvar = MVar(IO.async())
104+
* val mvar = MVar.factoryUncancelable(IO.async())
105105
*
106106
* mvar.empty<Int>().flatMap { v ->
107107
* v.tryPut(5)
108108
* }.unsafeRunSync() == true
109109
*
110-
* mvar.of(5).flatMap { v ->
110+
* mvar.just(5).flatMap { v ->
111111
* v.tryPut(10)
112112
* }.unsafeRunSync() == false
113113
* //sampleEnd
@@ -126,9 +126,9 @@ interface MVar<F, A> {
126126
*
127127
* fun main(args: Array<String>) {
128128
* //sampleStart
129-
* val mvar = MVar(IO.async())
129+
* val mvar = MVar.factoryUncancelable(IO.async())
130130
*
131-
* mvar.of(5).flatMap { v ->
131+
* mvar.just(5).flatMap { v ->
132132
* v.take()
133133
* }.unsafeRunSync() == 5
134134
*
@@ -152,9 +152,9 @@ interface MVar<F, A> {
152152
*
153153
* fun main(args: Array<String>) {
154154
* //sampleStart
155-
* val mvar = MVar(IO.async())
155+
* val mvar = MVar.factoryUncancelable(IO.async())
156156
*
157-
* mvar.of(5).flatMap { v ->
157+
* mvar.just(5).flatMap { v ->
158158
* v.tryTake()
159159
* }.unsafeRunSync() == Some(5)
160160
*
@@ -178,13 +178,13 @@ interface MVar<F, A> {
178178
* import arrow.effects.extensions.io.monad.map
179179
* fun main(args: Array<String>) {
180180
* //sampleStart
181-
* val mvar = MVar(IO.async())
181+
* val mvar = MVar.factoryUncancelable(IO.async())
182182
*
183-
* mvar.of(5).flatMap { v ->
183+
* mvar.just(5).flatMap { v ->
184184
* v.read()
185185
* }.unsafeRunSync() == 5
186186
*
187-
* mvar.of(5).flatMap { v ->
187+
* mvar.just(5).flatMap { v ->
188188
* v.read().flatMap { value ->
189189
* v.isNotEmpty().map { isNotEmpty ->
190190
* value toT isNotEmpty
@@ -221,7 +221,7 @@ interface MVar<F, A> {
221221
CancelableMVar.empty(CF)
222222

223223
/**
224-
* Create an uncancelable [MVar] that's initialized to an [initial] value.
224+
* Create a cancelable [MVar] that's initialized to an [initial] value.
225225
*
226226
* ```kotlin:ank:playground
227227
* import arrow.effects.*
@@ -288,18 +288,18 @@ interface MVar<F, A> {
288288
fun <F, A> uncancelableOf(initial: A, AS: Async<F>): Kind<F, MVar<F, A>> =
289289
UncancelableMVar(initial, AS)
290290

291-
operator fun <F> invoke(AS: Async<F>) = object : MVarPartialOf<F> {
291+
fun <F> factoryUncancelable(AS: Async<F>) = object : MVarFactory<F> {
292292

293-
override fun <A> of(a: A): Kind<F, MVar<F, A>> =
293+
override fun <A> just(a: A): Kind<F, MVar<F, A>> =
294294
UncancelableMVar(a, AS)
295295

296296
override fun <A> empty(): Kind<F, MVar<F, A>> =
297297
UncancelableMVar.empty(AS)
298298
}
299299

300-
operator fun <F> invoke(CF: Concurrent<F>) = object : MVarPartialOf<F> {
300+
fun <F> factoryCancelable(CF: Concurrent<F>) = object : MVarFactory<F> {
301301

302-
override fun <A> of(a: A): Kind<F, MVar<F, A>> =
302+
override fun <A> just(a: A): Kind<F, MVar<F, A>> =
303303
CancelableMVar(a, CF)
304304

305305
override fun <A> empty(): Kind<F, MVar<F, A>> =
@@ -318,14 +318,14 @@ interface MVar<F, A> {
318318
*
319319
* fun main(args: Array<String>) {
320320
* //sampleStart
321-
* val mvarPartial: MVarPartialOf<ForIO> = MVar(IO.async())
322-
* val intVar: IOOf<MVar<ForIO, Int>> = mvarPartial.of(5)
321+
* val mvarPartial: MVarFactory<ForIO> = MVar.factoryUncancelable(IO.async())
322+
* val intVar: IOOf<MVar<ForIO, Int>> = mvarPartial.just(5)
323323
* val stringVar: IOOf<MVar<ForIO, String>> = mvarPartial.empty<String>()
324324
* //sampleEnd
325325
* }
326326
* ```
327327
*/
328-
interface MVarPartialOf<F> {
328+
interface MVarFactory<F> {
329329

330330
/**
331331
* Builds a [MVar] with a value of type [A].
@@ -336,13 +336,13 @@ interface MVarPartialOf<F> {
336336
*
337337
* fun main(args: Array<String>) {
338338
* //sampleStart
339-
* val mvarPartial: MVarPartialOf<ForIO> = MVar(IO.async())
340-
* val intVar: IOOf<MVar<ForIO, Int>> = mvarPartial.of(5)
339+
* val mvarPartial: MVarFactory<ForIO> = MVar.factoryUncancelable(IO.async())
340+
* val intVar: IOOf<MVar<ForIO, Int>> = mvarPartial.just(5)
341341
* //sampleEnd
342342
* }
343343
* ```
344344
*/
345-
fun <A> of(a: A): Kind<F, MVar<F, A>>
345+
fun <A> just(a: A): Kind<F, MVar<F, A>>
346346

347347
/**
348348
* Builds an empty [MVar] for type [A].
@@ -353,7 +353,7 @@ interface MVarPartialOf<F> {
353353
*
354354
* fun main(args: Array<String>) {
355355
* //sampleStart
356-
* val mvarPartial: MVarPartialOf<ForIO> = MVar(IO.async())
356+
* val mvarPartial: MVarFactory<ForIO> = MVar.factoryUncancelable(IO.async())
357357
* val stringVar: IOOf<MVar<ForIO, String>> = mvarPartial.empty<String>()
358358
* //sampleEnd
359359
* }

modules/effects/arrow-effects-data/src/main/kotlin/arrow/effects/Ref.kt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -97,21 +97,21 @@ interface Ref<F, A> {
9797
* Builds a [Ref] value for data types given a [MonadDefer] instance
9898
* without deciding the type of the Ref's value.
9999
*
100-
* @see [of]
100+
* @see [invoke]
101101
*/
102-
operator fun <F> invoke(MD: MonadDefer<F>): PartiallyAppliedRef<F> = object : PartiallyAppliedRef<F> {
103-
override fun <A> of(a: A): Kind<F, Ref<F, A>> = Ref.of(a, MD)
102+
fun <F> factory(MD: MonadDefer<F>): RefFactory<F> = object : RefFactory<F> {
103+
override fun <A> delay(a: () -> A): Kind<F, Ref<F, A>> = invoke(MD, a)
104104
}
105105

106106
/**
107-
* Creates an asynchronous, concurrent mutable reference initialized to the supplied value.
107+
* Creates an asynchronous, concurrent mutable reference initialized using the supplied function.
108108
*/
109-
fun <F, A> of(a: A, MD: MonadDefer<F>): Kind<F, Ref<F, A>> = MD.delay {
110-
unsafe(a, MD)
109+
operator fun <F, A> invoke(MD: MonadDefer<F>, f: () -> A): Kind<F, Ref<F, A>> = MD.delay {
110+
unsafe(f(), MD)
111111
}
112112

113113
/**
114-
* Like [of] but returns the newly allocated ref directly instead of wrapping it in [MonadDefer.invoke].
114+
* Like [invoke] but returns the newly allocated ref directly instead of wrapping it in [MonadDefer.invoke].
115115
* This method is considered unsafe because it is not referentially transparent -- it allocates mutable state.
116116
*
117117
* @see [invoke]
@@ -185,8 +185,8 @@ interface Ref<F, A> {
185185
}
186186

187187
/**
188-
* Intermediate interface to partially apply [F] to [Ref].
188+
* Creates [Ref] for a kind [F] using a supplied function.
189189
*/
190-
interface PartiallyAppliedRef<F> {
191-
fun <A> of(a: A): Kind<F, Ref<F, A>>
190+
interface RefFactory<F> {
191+
fun <A> delay(a: () -> A): Kind<F, Ref<F, A>>
192192
}

modules/effects/arrow-effects-data/src/main/kotlin/arrow/effects/Semaphore.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ interface Semaphore<F> {
204204
*/
205205
operator fun <F> invoke(n: Long, CF: Concurrent<F>): Kind<F, Semaphore<F>> = CF.run {
206206
assertNonNegative(n).flatMap {
207-
Ref.of<F, State<F>>(Right(n), CF).map { ref ->
207+
Ref<F, State<F>>(CF) { Right(n) }.map { ref ->
208208
DefaultSemaphore(ref, Promise(this), this)
209209
}
210210
}
@@ -226,7 +226,7 @@ interface Semaphore<F> {
226226
*/
227227
fun <F> uncancelable(n: Long, AS: Async<F>): Kind<F, Semaphore<F>> = AS.run {
228228
assertNonNegative(n).flatMap {
229-
Ref.of<F, State<F>>(Right(n), AS).map { ref ->
229+
Ref<F, State<F>>(AS) { Right(n) }.map { ref ->
230230
DefaultSemaphore(ref, Promise.uncancelable(this), this)
231231
}
232232
}

modules/effects/arrow-effects-data/src/main/kotlin/arrow/effects/typeclasses/Concurrent.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import arrow.core.right
1111
import arrow.core.toT
1212
import arrow.effects.CancelToken
1313
import arrow.effects.KindConnection
14+
import arrow.effects.MVar
1415
import arrow.effects.data.internal.BindingCancellationException
1516
import arrow.typeclasses.MonadContinuation
1617
import java.util.concurrent.atomic.AtomicReference
@@ -681,6 +682,11 @@ interface Concurrent<F> : Async<F> {
681682
raceN(i, j)
682683
)
683684

685+
/**
686+
* Creates a variable [MVar] to be used for thread-sharing, initialized to a value [a]
687+
*/
688+
fun <A> mVar(a: A): Kind<F, MVar<F, A>> = MVar(a, this)
689+
684690
/**
685691
* Overload for [Async.asyncF]
686692
*

modules/effects/arrow-effects-data/src/main/kotlin/arrow/effects/typeclasses/MonadDefer.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import arrow.Kind
44
import arrow.core.Either
55
import arrow.core.Tuple2
66
import arrow.core.toT
7+
import arrow.effects.Ref
78
import arrow.effects.data.internal.BindingCancellationException
89
import arrow.typeclasses.MonadContinuation
910
import arrow.typeclasses.MonadError
@@ -36,6 +37,11 @@ interface MonadDefer<F> : MonadThrow<F>, Bracket<F, Throwable> {
3637
fun <A> delayOrRaise(f: () -> Either<Throwable, A>): Kind<F, A> =
3738
defer { f().fold({ raiseError<A>(it) }, { just(it) }) }
3839

40+
/**
41+
* Creates a [Ref] to purely manage mutable state, initialized by the function [f]
42+
*/
43+
fun <A> ref(f: () -> A): Kind<F, Ref<F, A>> = Ref(this, f)
44+
3945
/**
4046
* Entry point for monad bindings which enables for comprehensions. The underlying impl is based on coroutines.
4147
* A coroutines is initiated and inside [MonadDeferCancellableContinuation] suspended yielding to [Monad.flatMap]. Once all the flatMap binds are completed

modules/effects/arrow-effects-data/src/test/kotlin/arrow/effects/MVarTest.kt

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import arrow.core.Some
55
import arrow.core.Tuple3
66
import arrow.core.Tuple4
77
import arrow.core.Tuple7
8-
import arrow.core.flatMap
98
import arrow.core.toT
109
import arrow.effects.extensions.io.async.async
1110
import arrow.effects.extensions.io.concurrent.concurrent
@@ -25,7 +24,7 @@ class MVarTest : UnitSpec() {
2524

2625
init {
2726

28-
fun tests(label: String, mvar: MVarPartialOf<ForIO>) {
27+
fun tests(label: String, mvar: MVarFactory<ForIO>) {
2928
"$label - empty; put; isNotEmpty; take; put; take" {
3029
forAll(Gen.int(), Gen.int()) { a, b ->
3130
binding {
@@ -118,7 +117,7 @@ class MVarTest : UnitSpec() {
118117
"$label - initial; isNotEmpty; take; put; take" {
119118
forAll(Gen.int(), Gen.int()) { a, b ->
120119
binding {
121-
val av = mvar.of(a).bind()
120+
val av = mvar.just(a).bind()
122121
val isNotEmpty = av.isNotEmpty().bind()
123122
val r1 = av.take().bind()
124123
av.put(b).bind()
@@ -132,7 +131,7 @@ class MVarTest : UnitSpec() {
132131
"$label - initial; read; take" {
133132
forAll(Gen.int()) { i ->
134133
binding {
135-
val av = mvar.of(i).bind()
134+
val av = mvar.just(i).bind()
136135
val read = av.read().bind()
137136
val take = av.take().bind()
138137
read toT take
@@ -156,12 +155,12 @@ class MVarTest : UnitSpec() {
156155
}
157156

158157
val count = 10000
159-
val task = mvar.of(1).flatMap { ch -> loop(count, 0, ch) }
158+
val task = mvar.just(1).flatMap { ch -> loop(count, 0, ch) }
160159
task.equalUnderTheLaw(IO.just(count), EQ())
161160
}
162161
}
163162

164-
tests("UncancelableMVar", MVar(IO.async()))
165-
tests("CancelableMVar", MVar(IO.concurrent()))
163+
tests("UncancelableMVar", MVar.factoryUncancelable(IO.async()))
164+
tests("CancelableMVar", MVar.factoryUncancelable(IO.concurrent()))
166165
}
167166
}

modules/effects/arrow-effects-data/src/test/kotlin/arrow/effects/PromiseTest.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,18 @@ import arrow.core.Left
44
import arrow.core.None
55
import arrow.core.Some
66
import arrow.core.Tuple2
7-
import arrow.effects.extensions.io.apply.product
87
import arrow.effects.extensions.io.applicativeError.attempt
8+
import arrow.effects.extensions.io.apply.product
99
import arrow.effects.extensions.io.async.async
1010
import arrow.effects.extensions.io.concurrent.concurrent
1111
import arrow.effects.extensions.io.functor.tupleLeft
1212
import arrow.effects.extensions.io.monad.flatMap
1313
import arrow.effects.extensions.io.monadDefer.monadDefer
1414
import arrow.test.UnitSpec
1515
import arrow.test.generators.throwable
16-
import io.kotlintest.runner.junit4.KotlinTestRunner
1716
import io.kotlintest.properties.Gen
1817
import io.kotlintest.properties.forAll
18+
import io.kotlintest.runner.junit4.KotlinTestRunner
1919
import io.kotlintest.shouldBe
2020
import kotlinx.coroutines.Dispatchers
2121
import org.junit.runner.RunWith
@@ -122,7 +122,7 @@ class PromiseTest : UnitSpec() {
122122
}
123123

124124
"$label - get blocks until set" {
125-
Ref.of(0, IO.monadDefer()).flatMap { state ->
125+
Ref(IO.monadDefer()) { 0 }.flatMap { state ->
126126
promise.flatMap { modifyGate ->
127127
promise.flatMap { readGate ->
128128
modifyGate.get().flatMap { state.update { i -> i * 2 }.flatMap { readGate.complete(0) } }.startFiber(ctx).flatMap {

0 commit comments

Comments
 (0)