From c675811ab9b727590a89eb95958025086b855960 Mon Sep 17 00:00:00 2001 From: franciscodr Date: Thu, 2 Feb 2023 16:31:52 +0100 Subject: [PATCH 01/25] Deprecate foldable methods --- .../commonMain/kotlin/arrow/core/Option.kt | 124 ++++++++++++++++-- 1 file changed, 114 insertions(+), 10 deletions(-) diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt index 0c86bd2ccbe..a26b6ac90ae 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt @@ -679,18 +679,30 @@ public sealed class Option { public inline fun all(predicate: (A) -> Boolean): Boolean = fold({ true }, predicate) + @Deprecated( + NicheAPI + "Prefer using the Option DSL or fold", + ReplaceWith("fold>>({ None }) { value -> f(value).map(::Some) }") + ) public inline fun crosswalk(f: (A) -> Option): Option> = when (this) { is None -> this is Some -> f(value).map { Some(it) } } + @Deprecated( + NicheAPI + "Prefer using the Option DSL or fold", + ReplaceWith("fold>>({ emptyMap() }) { value -> f(value).mapValues { Some(it.value) } }") + ) public inline fun crosswalkMap(f: (A) -> Map): Map> = when (this) { is None -> emptyMap() is Some -> f(value).mapValues { Some(it.value) } } + @Deprecated( + NicheAPI + "Prefer using the Option DSL or fold", + ReplaceWith("fold?>({ null }) { value -> f(value)?.let(::Some) }") + ) public inline fun crosswalkNull(f: (A) -> B?): Option? = when (this) { is None -> null @@ -767,10 +779,18 @@ public sealed class Option { is None -> null } + @Deprecated( + NicheAPI + "Prefer when or fold instead", + ReplaceWith("MB.run { this.fold({ empty() }) {a -> empty().combine(f(a)) } }") + ) public inline fun foldMap(MB: Monoid, f: (A) -> B): B = MB.run { foldLeft(empty()) { b, a -> b.combine(f(a)) } } + @Deprecated( + NicheAPI + "Prefer when or fold instead", + ReplaceWith("fold({ initial }) { operation(initial, it) }") + ) public inline fun foldLeft(initial: B, operation: (B, A) -> B): B = when (this) { is Some -> operation(initial, value) @@ -795,12 +815,20 @@ public sealed class Option { ) } + @Deprecated( + NicheAPI + "Prefer when or fold instead", + ReplaceWith("fold({ null }) { value -> operation(initial(value), value) }") + ) public inline fun reduceOrNull(initial: (A) -> B, operation: (acc: B, A) -> B): B? = when (this) { is None -> null is Some -> operation(initial(value), value) } + @Deprecated( + NicheAPI + "Prefer when or fold instead", + ReplaceWith("fold({ Eval.now(null) }) { value -> operation(value, Eval.now(initial(value))) }") + ) public inline fun reduceRightEvalOrNull( initial: (A) -> B, operation: (A, acc: Eval) -> Eval @@ -813,11 +841,23 @@ public sealed class Option { public fun replicate(n: Int): Option> = if (n <= 0) Some(emptyList()) else map { a -> List(n) { a } } + @Deprecated( + NicheAPI + "Prefer using the Option DSL, or explicit fold or when", + ReplaceWith( + "fold({ emptyList() }) { a -> fa(a).map(::Some) }", + "arrow.core.Some") + ) @OptIn(ExperimentalTypeInference::class) @OverloadResolutionByLambdaReturnType public inline fun traverse(fa: (A) -> Iterable): List> = fold({ emptyList() }, { a -> fa(a).map { Some(it) } }) + @Deprecated( + NicheAPI + "Prefer using the Option DSL, or explicit fold or when", + ReplaceWith( + "fold({ Right(None) }) { a -> fa(a).map(::Some) }", + "arrow.core.Either.Right") + ) @OptIn(ExperimentalTypeInference::class) @OverloadResolutionByLambdaReturnType public inline fun traverse(fa: (A) -> Either): Either> = @@ -830,6 +870,12 @@ public sealed class Option { public inline fun traverseEither(fa: (A) -> Either): Either> = traverse(fa) + @Deprecated( + NicheAPI + "Prefer using the Option DSL, or explicit fold or when", + ReplaceWith( + "fold({ Valid(None) }) { a -> fa(a).map(::Some) }", + "arrow.core.Valid") + ) @OptIn(ExperimentalTypeInference::class) @OverloadResolutionByLambdaReturnType public inline fun traverse(fa: (A) -> Validated): Validated> = @@ -985,11 +1031,20 @@ public fun Option.salign(SA: Semigroup, b: Option): Option = * @receiver Option of Either * @return a tuple containing Option of [Either.Left] and another Option of its [Either.Right] value. */ -public fun Option>.separateEither(): Pair, Option> { - val asep = flatMap { gab -> gab.fold({ Some(it) }, { None }) } - val bsep = flatMap { gab -> gab.fold({ None }, { Some(it) }) } - return asep to bsep -} +@Deprecated( + NicheAPI + "Prefer using the Option DSL, or explicit fold or when", + ReplaceWith( + "fold({ None to None }) { either -> either.fold, Option>>({ Some(it) to None }, { None to Some(it) }) }", + "arrow.core.None", "arrow.core.Some" + ) +) +public fun Option>.separateEither(): Pair, Option> = + fold({ None to None }) { either -> + either.fold( + { Some(it) to None }, + { None to Some(it) } + ) + } /** * Separate the inner [Validated] value into the [Validated.Invalid] and [Validated.Valid]. @@ -997,12 +1052,28 @@ public fun Option>.separateEither(): Pair, Option< * @receiver Option of Either * @return a tuple containing Option of [Validated.Invalid] and another Option of its [Validated.Valid] value. */ -public fun Option>.separateValidated(): Pair, Option> { - val asep = flatMap { gab -> gab.fold({ Some(it) }, { None }) } - val bsep = flatMap { gab -> gab.fold({ None }, { Some(it) }) } - return asep to bsep -} +@Deprecated( + NicheAPI + "Prefer using the Option DSL, or explicit fold or when", + ReplaceWith( + "fold({ None to None }) { validated -> validated.fold, Option>>({ Some(it) to None }, { None to Some(it) }) }", + "arrow.core.None", "arrow.core.Some" + ) +) +public fun Option>.separateValidated(): Pair, Option> = + fold({ None to None }) { validated -> + validated.fold( + { Some(it) to None }, + { None to Some(it) } + ) + } +@Deprecated( + "Prefer using the Option DSL, or explicit fold or when", + ReplaceWith( + "fold({ emptyList() }) { a -> fa(a).map(::Some) }", + "arrow.core.Some", + ) +) public fun Option>.sequence(): List> = traverse(::identity) @@ -1010,6 +1081,12 @@ public fun Option>.sequence(): List> = public fun Option>.sequenceEither(): Either> = sequence() +@Deprecated( + NicheAPI + "Prefer using the Option DSL, or explicit fold or when", + ReplaceWith( + "fold({ Right(None) }) { a -> fa(a).map(::Some) }", + "arrow.core.Either.Right") +) public fun Option>.sequence(): Either> = traverse(::identity) @@ -1017,6 +1094,12 @@ public fun Option>.sequence(): Either> = public fun Option>.sequenceValidated(): Validated> = sequence() +@Deprecated( + NicheAPI + "Prefer using the Option DSL, or explicit fold or when", + ReplaceWith( + "fold({ Valid(None) }) { a -> fa(a).map(::Some) }", + "arrow.core.Valid") +) public fun Option>.sequence(): Validated> = traverse(::identity) @@ -1033,16 +1116,37 @@ public inline fun Option.unalign(f: (C) -> Ior): Pair iterable.fold(MA) }", + "arrow.typeclasses.Monoid" + ) +) public fun Option>.unite(MA: Monoid): Option = map { iterable -> iterable.fold(MA) } +@Deprecated( + NicheAPI + "Prefer using the Option DSL or explicit flatMap", + ReplaceWith( + "flatMap { either -> either.fold>({ None }, ::Some) }", + "arrow.core.Option", "arrow.core.Some" + ) +) public fun Option>.uniteEither(): Option = flatMap { either -> either.fold({ None }, { b -> Some(b) }) } +@Deprecated( + NicheAPI + "Prefer using the Option DSL or explicit flatMap", + ReplaceWith( + "flatMap { validated -> validated.fold>({ None }, ::Some) }", + "arrow.core.Option", "arrow.core.Some" + ) +) public fun Option>.uniteValidated(): Option = flatMap { validated -> validated.fold({ None }, { b -> Some(b) }) From 268c9952c99bf53a6527fdc24130ebeee1ecf49c Mon Sep 17 00:00:00 2001 From: franciscodr Date: Sat, 4 Feb 2023 09:27:07 +0100 Subject: [PATCH 02/25] Deprecate functor/applicative/monad methods --- .../commonMain/kotlin/arrow/core/Option.kt | 145 ++++++++++++++---- .../kotlin/examples/example-option-19.kt | 4 +- .../kotlin/examples/example-option-20.kt | 4 +- .../kotlin/examples/example-option-21.kt | 10 +- .../kotlin/examples/example-option-22.kt | 10 +- .../kotlin/examples/example-option-23.kt | 11 ++ .../kotlin/examples/example-option-24.kt | 14 ++ .../kotlin/examples/example-option-25.kt | 3 + 8 files changed, 156 insertions(+), 45 deletions(-) create mode 100644 arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-24.kt create mode 100644 arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-25.kt diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt index a26b6ac90ae..fe000c68e0b 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt @@ -3,6 +3,9 @@ package arrow.core import arrow.core.Either.Right import arrow.typeclasses.Monoid import arrow.typeclasses.Semigroup +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract import kotlin.experimental.ExperimentalTypeInference import kotlin.jvm.JvmName import kotlin.jvm.JvmStatic @@ -418,6 +421,58 @@ public sealed class Option { Some.unit ) { b, c, d, _, _, _, _, _, _, _ -> map(b, c, d) } + /** + * The given function is applied as a fire and forget effect + * if this is a `None`. + * When applied the result is ignored and the original + * None value is returned + * + * Example: + * ```kotlin + * import arrow.core.Some + * import arrow.core.none + * + * fun main() { + * Some(12).onNone { println("flower") } // Result: Some(12) + * none().onNone { println("flower") } // Result: prints "flower" and returns: None + * } + * ``` + * + */ + @OptIn(ExperimentalContracts::class) + public inline fun onNone(action: () -> Unit): Option { + contract { + callsInPlace(action, InvocationKind.AT_MOST_ONCE) + } + return also { if (it.isEmpty()) action() } + } + + /** + * The given function is applied as a fire and forget effect + * if this is a `some`. + * When applied the result is ignored and the original + * Some value is returned + * + * Example: + * ```kotlin + * import arrow.core.Some + * import arrow.core.none + * + * fun main() { + * Some(12).onSome { println("flower") } // Result: prints "flower" and returns: Some(12) + * none().onSome { println("flower") } // Result: None + * } + * ``` + * + */ + @OptIn(ExperimentalContracts::class) + public inline fun onSome(action: (A) -> Unit): Option { + contract { + callsInPlace(action, InvocationKind.AT_MOST_ONCE) + } + return also { if (it.isNotEmpty()) action(it.value) } + } + /** * The given function is applied as a fire and forget effect * if this is a `None`. @@ -434,16 +489,14 @@ public sealed class Option { * none().tapNone { println("flower") } // Result: prints "flower" and returns: None * } * ``` - * + * */ + @Deprecated( + "tapNone is being renamed to onNone to be more consistent with the Kotlin Standard Library naming", + ReplaceWith("onNone(f)") + ) public inline fun tapNone(f: () -> Unit): Option = - when (this) { - is None -> { - f() - this - } - is Some -> this - } + onNone(f) /** * The given function is applied as a fire and forget effect @@ -461,16 +514,14 @@ public sealed class Option { * none().tap { println("flower") } // Result: None * } * ``` - * + * */ + @Deprecated( + "tap is being renamed to onNone to be more consistent with the Kotlin Standard Library naming", + ReplaceWith("onSome(f)") + ) public inline fun tap(f: (A) -> Unit): Option = - when (this) { - is None -> this - is Some -> { - f(this.value) - this - } - } + onSome(f) public inline fun zip( b: Option, @@ -584,9 +635,16 @@ public sealed class Option { * Returns true if the option is [None], false otherwise. * @note Used only for performance instead of fold. */ - public abstract fun isEmpty(): Boolean - - public fun isNotEmpty(): Boolean = !isEmpty() + @OptIn(ExperimentalContracts::class) + public fun isEmpty(): Boolean { + contract { returns(true) implies (this@Option is None) } + return this@Option is None + } + @OptIn(ExperimentalContracts::class) + public fun isNotEmpty(): Boolean { + contract { returns(true) implies (this@Option is Some) } + return this@Option is Some + } /** * alias for [isDefined] @@ -676,6 +734,10 @@ public sealed class Option { * * @param predicate the predicate to test */ + @Deprecated( + NicheAPI + "Prefer using the Option DSL, or fold or map", + ReplaceWith("fold({ false }, predicate)") + ) public inline fun all(predicate: (A) -> Boolean): Boolean = fold({ true }, predicate) @@ -746,10 +808,14 @@ public sealed class Option { * none.exists { it > 10 } // Result: false * } * ``` - * + * * * @param predicate the predicate to test */ + @Deprecated( + NicheAPI + "Prefer using the Option DSL, or fold or map", + ReplaceWith("fold({ true }, predicate)") + ) public inline fun exists(predicate: (A) -> Boolean): Boolean = fold({ false }, predicate) /** @@ -771,8 +837,12 @@ public sealed class Option { * none.exists { it > 10 } // Result: null * } * ``` - * + * */ + @Deprecated( + NicheAPI + "Prefer Kotlin nullable syntax instead", + ReplaceWith("getOrNull()?.takeIf(predicate)") + ) public inline fun findOrNull(predicate: (A) -> Boolean): A? = when (this) { is Some -> if (predicate(value)) value else null @@ -838,6 +908,10 @@ public sealed class Option { is Some -> operation(value, Eval.now(initial(value))) } + @Deprecated( + NicheAPI + "Prefer using the Option DSL or map", + ReplaceWith("map { List(n) { it } }") + ) public fun replicate(n: Int): Option> = if (n <= 0) Some(emptyList()) else map { a -> List(n) { a } } @@ -893,11 +967,23 @@ public sealed class Option { public fun toList(): List = fold(::emptyList) { listOf(it) } + @Deprecated( + RedundantAPI + "Replace with map with Unit", + ReplaceWith("map { }") + ) public fun void(): Option = - map { Unit } + map { } + @Deprecated( + NicheAPI + "Prefer using the Option DSL or map", + ReplaceWith("map { left to it }") + ) public fun pairLeft(left: L): Option> = this.map { left to it } + @Deprecated( + NicheAPI + "Prefer using the Option DSL or map", + ReplaceWith("map { it to right }") + ) public fun pairRight(right: R): Option> = this.map { it to right } public infix fun and(value: Option): Option = if (isEmpty()) { @@ -913,18 +999,15 @@ public sealed class Option { } public object None : Option() { - override fun isEmpty(): Boolean = true - override fun toString(): String = "Option.None" } public data class Some(val value: T) : Option() { - override fun isEmpty(): Boolean = false - override fun toString(): String = "Option.Some($value)" public companion object { @PublishedApi + @Deprecated("Unused, will be removed from bytecode in Arrow 2.x.x", ReplaceWith("Some(Unit)")) internal val unit: Option = Some(Unit) } } @@ -973,6 +1056,10 @@ public fun Iterable>.combineAll(MA: Monoid): Option = public fun Option.combineAll(MA: Monoid): A = getOrElse { MA.empty() } +@Deprecated( + RedundantAPI + "Prefer if-else statement inside option DSL, or replace with explicit flatMap", + ReplaceWith("this.flatMap { b -> b.takeIf(predicate)?.let(::Some) ?: None.also(error) }") +) public inline fun Option.ensure(error: () -> Unit, predicate: (A) -> Boolean): Option = when (this) { is Some -> @@ -1010,6 +1097,10 @@ public inline fun Option.redeem(fe: (Unit) -> B, fb: (A) -> B): Option public inline fun Option.redeemWith(fe: (Unit) -> Option, fb: (A) -> Option): Option = flatMap(fb).handleErrorWith(fe) +@Deprecated( + NicheAPI + "Prefer using the Option DSL or map", + ReplaceWith("MA.run { this.map { List(n) { it }.fold(empty()) { acc, v -> acc + v } } }") +) public fun Option.replicate(n: Int, MA: Monoid): Option = MA.run { if (n <= 0) Some(empty()) else map { a -> List(n) { a }.fold(empty()) { acc, v -> acc + v } } @@ -1179,7 +1270,7 @@ public inline fun Option.unzip(f: (C) -> Pair): Pair + * */ public fun Option.widen(): Option = this diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-19.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-19.kt index 364813486b9..1d9d8da23c4 100644 --- a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-19.kt +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-19.kt @@ -5,6 +5,6 @@ import arrow.core.Some import arrow.core.none fun main() { - Some(12).tapNone { println("flower") } // Result: Some(12) - none().tapNone { println("flower") } // Result: prints "flower" and returns: None + Some(12).onNone { println("flower") } // Result: Some(12) + none().onNone { println("flower") } // Result: prints "flower" and returns: None } diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-20.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-20.kt index 2e5652f4aac..0813a51550a 100644 --- a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-20.kt +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-20.kt @@ -5,6 +5,6 @@ import arrow.core.Some import arrow.core.none fun main() { - Some(12).tap { println("flower") } // Result: prints "flower" and returns: Some(12) - none().tap { println("flower") } // Result: None + Some(12).onSome { println("flower") } // Result: prints "flower" and returns: Some(12) + none().onSome { println("flower") } // Result: None } diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-21.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-21.kt index 07a9d4ec693..fd454d93f83 100644 --- a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-21.kt +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-21.kt @@ -2,13 +2,9 @@ package arrow.core.examples.exampleOption21 import arrow.core.Some -import arrow.core.None -import arrow.core.Option +import arrow.core.none fun main() { - Some(12).exists { it > 10 } // Result: true - Some(7).exists { it > 10 } // Result: false - - val none: Option = None - none.exists { it > 10 } // Result: false + Some(12).tapNone { println("flower") } // Result: Some(12) + none().tapNone { println("flower") } // Result: prints "flower" and returns: None } diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-22.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-22.kt index 9263fd76499..4b454526514 100644 --- a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-22.kt +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-22.kt @@ -2,13 +2,9 @@ package arrow.core.examples.exampleOption22 import arrow.core.Some -import arrow.core.None -import arrow.core.Option +import arrow.core.none fun main() { - Some(12).exists { it > 10 } // Result: 12 - Some(7).exists { it > 10 } // Result: null - - val none: Option = None - none.exists { it > 10 } // Result: null + Some(12).tap { println("flower") } // Result: prints "flower" and returns: Some(12) + none().tap { println("flower") } // Result: None } diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-23.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-23.kt index dfcf262a5ae..7169f9721cf 100644 --- a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-23.kt +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-23.kt @@ -1,3 +1,14 @@ // This file was automatically generated from Option.kt by Knit tool. Do not edit. package arrow.core.examples.exampleOption23 +import arrow.core.Some +import arrow.core.None +import arrow.core.Option + +fun main() { + Some(12).exists { it > 10 } // Result: true + Some(7).exists { it > 10 } // Result: false + + val none: Option = None + none.exists { it > 10 } // Result: false +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-24.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-24.kt new file mode 100644 index 00000000000..754e087825a --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-24.kt @@ -0,0 +1,14 @@ +// This file was automatically generated from Option.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleOption24 + +import arrow.core.Some +import arrow.core.None +import arrow.core.Option + +fun main() { + Some(12).exists { it > 10 } // Result: 12 + Some(7).exists { it > 10 } // Result: null + + val none: Option = None + none.exists { it > 10 } // Result: null +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-25.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-25.kt new file mode 100644 index 00000000000..2d385208ab7 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-25.kt @@ -0,0 +1,3 @@ +// This file was automatically generated from Option.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleOption25 + From 8858cec8dcca3f2912e840098b7dd5626b57d31e Mon Sep 17 00:00:00 2001 From: franciscodr Date: Sat, 4 Feb 2023 08:32:06 +0000 Subject: [PATCH 03/25] Update API files --- arrow-libs/core/arrow-core/api/arrow-core.api | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arrow-libs/core/arrow-core/api/arrow-core.api b/arrow-libs/core/arrow-core/api/arrow-core.api index 549eb586836..83c430b863c 100644 --- a/arrow-libs/core/arrow-core/api/arrow-core.api +++ b/arrow-libs/core/arrow-core/api/arrow-core.api @@ -833,7 +833,6 @@ public final class arrow/core/NonFatalOrThrowKt { public final class arrow/core/None : arrow/core/Option { public static final field INSTANCE Larrow/core/None; - public fun isEmpty ()Z public fun toString ()Ljava/lang/String; } @@ -871,12 +870,14 @@ public abstract class arrow/core/Option { public static final fun fromNullable (Ljava/lang/Object;)Larrow/core/Option; public static final fun invoke (Ljava/lang/Object;)Larrow/core/Option; public final fun isDefined ()Z - public abstract fun isEmpty ()Z + public final fun isEmpty ()Z public final fun isNotEmpty ()Z public static final fun lift (Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function1; public final fun map (Lkotlin/jvm/functions/Function1;)Larrow/core/Option; public final fun mapNotNull (Lkotlin/jvm/functions/Function1;)Larrow/core/Option; public final fun nonEmpty ()Z + public final fun onNone (Lkotlin/jvm/functions/Function0;)Larrow/core/Option; + public final fun onSome (Lkotlin/jvm/functions/Function1;)Larrow/core/Option; public final fun orNull ()Ljava/lang/Object; public final fun padZip (Larrow/core/Option;)Larrow/core/Option; public final fun padZip (Larrow/core/Option;Lkotlin/jvm/functions/Function2;)Larrow/core/Option; @@ -1557,7 +1558,6 @@ public final class arrow/core/Some : arrow/core/Option { public fun equals (Ljava/lang/Object;)Z public final fun getValue ()Ljava/lang/Object; public fun hashCode ()I - public fun isEmpty ()Z public fun toString ()Ljava/lang/String; } From ea87f40da7a0091df503dfab646058970b855f04 Mon Sep 17 00:00:00 2001 From: Francisco Diaz Date: Sat, 4 Feb 2023 10:03:05 +0100 Subject: [PATCH 04/25] Apply suggestions from code review Co-authored-by: Simon Vergauwen --- .../commonMain/kotlin/arrow/core/Option.kt | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt index fe000c68e0b..ab2604021be 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt @@ -851,7 +851,7 @@ public sealed class Option { @Deprecated( NicheAPI + "Prefer when or fold instead", - ReplaceWith("MB.run { this.fold({ empty() }) {a -> empty().combine(f(a)) } }") + ReplaceWith("MB.run { this.fold({ empty() }) { a -> empty().combine(f(a)) } }") ) public inline fun foldMap(MB: Monoid, f: (A) -> B): B = MB.run { foldLeft(empty()) { b, a -> b.combine(f(a)) } @@ -897,7 +897,10 @@ public sealed class Option { @Deprecated( NicheAPI + "Prefer when or fold instead", - ReplaceWith("fold({ Eval.now(null) }) { value -> operation(value, Eval.now(initial(value))) }") + ReplaceWith( + "fold({ Eval.now(null) }) { value -> operation(value, Eval.now(initial(value))) }", + "arrow.core.Eval" + ) ) public inline fun reduceRightEvalOrNull( initial: (A) -> B, @@ -930,7 +933,10 @@ public sealed class Option { NicheAPI + "Prefer using the Option DSL, or explicit fold or when", ReplaceWith( "fold({ Right(None) }) { a -> fa(a).map(::Some) }", - "arrow.core.Either.Right") + "arrow.core.Either.Right", + "arrow.core.None", + "arrow.core.Some" + ) ) @OptIn(ExperimentalTypeInference::class) @OverloadResolutionByLambdaReturnType @@ -948,7 +954,10 @@ public sealed class Option { NicheAPI + "Prefer using the Option DSL, or explicit fold or when", ReplaceWith( "fold({ Valid(None) }) { a -> fa(a).map(::Some) }", - "arrow.core.Valid") + "arrow.core.Valid", + "arrow.core.None", + "arrow.core.Some" + ) ) @OptIn(ExperimentalTypeInference::class) @OverloadResolutionByLambdaReturnType @@ -1126,7 +1135,7 @@ public fun Option.salign(SA: Semigroup, b: Option): Option = NicheAPI + "Prefer using the Option DSL, or explicit fold or when", ReplaceWith( "fold({ None to None }) { either -> either.fold, Option>>({ Some(it) to None }, { None to Some(it) }) }", - "arrow.core.None", "arrow.core.Some" + "arrow.core.None", "arrow.core.Some", "arrow.core.Option" ) ) public fun Option>.separateEither(): Pair, Option> = @@ -1147,7 +1156,7 @@ public fun Option>.separateEither(): Pair, Option< NicheAPI + "Prefer using the Option DSL, or explicit fold or when", ReplaceWith( "fold({ None to None }) { validated -> validated.fold, Option>>({ Some(it) to None }, { None to Some(it) }) }", - "arrow.core.None", "arrow.core.Some" + "arrow.core.None", "arrow.core.Some", "arrow.core.Option" ) ) public fun Option>.separateValidated(): Pair, Option> = @@ -1176,7 +1185,10 @@ public fun Option>.sequenceEither(): Either> = NicheAPI + "Prefer using the Option DSL, or explicit fold or when", ReplaceWith( "fold({ Right(None) }) { a -> fa(a).map(::Some) }", - "arrow.core.Either.Right") + "arrow.core.Either.Right", + "arrow.core.None", + "arrow.core.Some" + ) ) public fun Option>.sequence(): Either> = traverse(::identity) @@ -1189,7 +1201,10 @@ public fun Option>.sequenceValidated(): Validated fa(a).map(::Some) }", - "arrow.core.Valid") + "arrow.core.Valid", + "arrow.core.None", + "arrow.core.Some" + ) ) public fun Option>.sequence(): Validated> = traverse(::identity) @@ -1223,7 +1238,7 @@ public fun Option>.unite(MA: Monoid): Option = NicheAPI + "Prefer using the Option DSL or explicit flatMap", ReplaceWith( "flatMap { either -> either.fold>({ None }, ::Some) }", - "arrow.core.Option", "arrow.core.Some" + "arrow.core.Option", "arrow.core.Some", "arrow.core.None" ) ) public fun Option>.uniteEither(): Option = @@ -1235,7 +1250,7 @@ public fun Option>.uniteEither(): Option = NicheAPI + "Prefer using the Option DSL or explicit flatMap", ReplaceWith( "flatMap { validated -> validated.fold>({ None }, ::Some) }", - "arrow.core.Option", "arrow.core.Some" + "arrow.core.Option", "arrow.core.Some", "arrow.core.None" ) ) public fun Option>.uniteValidated(): Option = From fb8a3aad4ad6e3badcc338d846ce5a15778adb73 Mon Sep 17 00:00:00 2001 From: franciscodr Date: Sat, 4 Feb 2023 10:12:41 +0100 Subject: [PATCH 05/25] Add getOrNull method --- .../commonMain/kotlin/arrow/core/Option.kt | 47 ++++++++++++++++--- .../kotlin/examples/example-option-23.kt | 13 ++--- .../kotlin/examples/example-option-24.kt | 6 +-- .../kotlin/examples/example-option-25.kt | 11 +++++ .../kotlin/examples/example-option-26.kt | 3 ++ 5 files changed, 62 insertions(+), 18 deletions(-) create mode 100644 arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-26.kt diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt index ab2604021be..4bfd6d38ca5 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt @@ -657,8 +657,29 @@ public sealed class Option { */ public fun isDefined(): Boolean = !isEmpty() + @Deprecated( + "orNull is being renamed to getOrNull to be more consistent with the Kotlin Standard Library naming", + ReplaceWith("getOrNull()") + ) public fun orNull(): A? = fold({ null }, ::identity) + /** + * Returns the encapsulated value [A] if this instance represents [Some] or `null` if it is [None]. + * + * ```kotlin + * import arrow.core.None + * import arrow.core.Some + * import io.kotest.matchers.shouldBe + * + * fun test() { + * Some(12).getOrNull() shouldBe 12 + * None.getOrNull() shouldBe null + * } + * ``` + * + */ + public fun getOrNull(): A? = getOrElse { null } + /** * Returns a [Some<$B>] containing the result of applying $f to this $option's * value if this $option is nonempty. Otherwise return $none. @@ -743,7 +764,12 @@ public sealed class Option { @Deprecated( NicheAPI + "Prefer using the Option DSL or fold", - ReplaceWith("fold>>({ None }) { value -> f(value).map(::Some) }") + ReplaceWith( + "fold>>({ None }) { value -> f(value).map(::Some) }", + "arrow.core.None", + "arrow.core.Option", + "arrow.core.Some" + ) ) public inline fun crosswalk(f: (A) -> Option): Option> = when (this) { @@ -753,7 +779,11 @@ public sealed class Option { @Deprecated( NicheAPI + "Prefer using the Option DSL or fold", - ReplaceWith("fold>>({ emptyMap() }) { value -> f(value).mapValues { Some(it.value) } }") + ReplaceWith( + "fold>>({ emptyMap() }) { value -> f(value).mapValues { Some(it.value) } }", + "arrow.core.Option", + "arrow.core.Some" + ) ) public inline fun crosswalkMap(f: (A) -> Map): Map> = when (this) { @@ -763,7 +793,10 @@ public sealed class Option { @Deprecated( NicheAPI + "Prefer using the Option DSL or fold", - ReplaceWith("fold?>({ null }) { value -> f(value)?.let(::Some) }") + ReplaceWith( + "getOrNull()?.let { value -> f(value)?.let(::Some) }", + "arrow.core.Some" + ) ) public inline fun crosswalkNull(f: (A) -> B?): Option? = when (this) { @@ -808,7 +841,7 @@ public sealed class Option { * none.exists { it > 10 } // Result: false * } * ``` - * + * * * @param predicate the predicate to test */ @@ -837,7 +870,7 @@ public sealed class Option { * none.exists { it > 10 } // Result: null * } * ``` - * + * */ @Deprecated( NicheAPI + "Prefer Kotlin nullable syntax instead", @@ -887,7 +920,7 @@ public sealed class Option { @Deprecated( NicheAPI + "Prefer when or fold instead", - ReplaceWith("fold({ null }) { value -> operation(initial(value), value) }") + ReplaceWith("getOrNull()?.let { value -> operation(initial(value), value) }") ) public inline fun reduceOrNull(initial: (A) -> B, operation: (acc: B, A) -> B): B? = when (this) { @@ -1285,7 +1318,7 @@ public inline fun Option.unzip(f: (C) -> Pair): Pair + * */ public fun Option.widen(): Option = this diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-23.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-23.kt index 7169f9721cf..f614536b8ef 100644 --- a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-23.kt +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-23.kt @@ -1,14 +1,11 @@ // This file was automatically generated from Option.kt by Knit tool. Do not edit. package arrow.core.examples.exampleOption23 -import arrow.core.Some import arrow.core.None -import arrow.core.Option - -fun main() { - Some(12).exists { it > 10 } // Result: true - Some(7).exists { it > 10 } // Result: false +import arrow.core.Some +import io.kotest.matchers.shouldBe - val none: Option = None - none.exists { it > 10 } // Result: false +fun test() { + Some(12).getOrNull() shouldBe 12 + None.getOrNull() shouldBe null } diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-24.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-24.kt index 754e087825a..9d49c2783b9 100644 --- a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-24.kt +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-24.kt @@ -6,9 +6,9 @@ import arrow.core.None import arrow.core.Option fun main() { - Some(12).exists { it > 10 } // Result: 12 - Some(7).exists { it > 10 } // Result: null + Some(12).exists { it > 10 } // Result: true + Some(7).exists { it > 10 } // Result: false val none: Option = None - none.exists { it > 10 } // Result: null + none.exists { it > 10 } // Result: false } diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-25.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-25.kt index 2d385208ab7..36d68d125c4 100644 --- a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-25.kt +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-25.kt @@ -1,3 +1,14 @@ // This file was automatically generated from Option.kt by Knit tool. Do not edit. package arrow.core.examples.exampleOption25 +import arrow.core.Some +import arrow.core.None +import arrow.core.Option + +fun main() { + Some(12).exists { it > 10 } // Result: 12 + Some(7).exists { it > 10 } // Result: null + + val none: Option = None + none.exists { it > 10 } // Result: null +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-26.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-26.kt new file mode 100644 index 00000000000..d874951efa7 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-26.kt @@ -0,0 +1,3 @@ +// This file was automatically generated from Option.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleOption26 + From 439773d67a8784925f2198d2a73da8d27cf6b1f2 Mon Sep 17 00:00:00 2001 From: franciscodr Date: Sat, 4 Feb 2023 09:16:49 +0000 Subject: [PATCH 06/25] Update API files --- arrow-libs/core/arrow-core/api/arrow-core.api | 1 + 1 file changed, 1 insertion(+) diff --git a/arrow-libs/core/arrow-core/api/arrow-core.api b/arrow-libs/core/arrow-core/api/arrow-core.api index 83c430b863c..1c2a8b4ce55 100644 --- a/arrow-libs/core/arrow-core/api/arrow-core.api +++ b/arrow-libs/core/arrow-core/api/arrow-core.api @@ -868,6 +868,7 @@ public abstract class arrow/core/Option { public final fun foldLeft (Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public final fun foldMap (Larrow/typeclasses/Monoid;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; public static final fun fromNullable (Ljava/lang/Object;)Larrow/core/Option; + public final fun getOrNull ()Ljava/lang/Object; public static final fun invoke (Ljava/lang/Object;)Larrow/core/Option; public final fun isDefined ()Z public final fun isEmpty ()Z From 2d4cb4091643717fdddb05f63b3ab4ea8d74be6c Mon Sep 17 00:00:00 2001 From: franciscodr Date: Sat, 4 Feb 2023 12:15:33 +0100 Subject: [PATCH 07/25] Restore isEmpty implementation --- .../src/commonMain/kotlin/arrow/core/Option.kt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt index 4bfd6d38ca5..319a84bde9d 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt @@ -635,11 +635,8 @@ public sealed class Option { * Returns true if the option is [None], false otherwise. * @note Used only for performance instead of fold. */ - @OptIn(ExperimentalContracts::class) - public fun isEmpty(): Boolean { - contract { returns(true) implies (this@Option is None) } - return this@Option is None - } + public abstract fun isEmpty(): Boolean + @OptIn(ExperimentalContracts::class) public fun isNotEmpty(): Boolean { contract { returns(true) implies (this@Option is Some) } @@ -1041,10 +1038,14 @@ public sealed class Option { } public object None : Option() { + public override fun isEmpty(): Boolean = true + override fun toString(): String = "Option.None" } public data class Some(val value: T) : Option() { + public override fun isEmpty(): Boolean = false + override fun toString(): String = "Option.Some($value)" public companion object { From 4165ee991bd01a03bef43a70cb72361fb589c6cf Mon Sep 17 00:00:00 2001 From: franciscodr Date: Sat, 4 Feb 2023 11:20:49 +0000 Subject: [PATCH 08/25] Update API files --- arrow-libs/core/arrow-core/api/arrow-core.api | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arrow-libs/core/arrow-core/api/arrow-core.api b/arrow-libs/core/arrow-core/api/arrow-core.api index 1c2a8b4ce55..e1fb45e74c5 100644 --- a/arrow-libs/core/arrow-core/api/arrow-core.api +++ b/arrow-libs/core/arrow-core/api/arrow-core.api @@ -833,6 +833,7 @@ public final class arrow/core/NonFatalOrThrowKt { public final class arrow/core/None : arrow/core/Option { public static final field INSTANCE Larrow/core/None; + public fun isEmpty ()Z public fun toString ()Ljava/lang/String; } @@ -871,7 +872,7 @@ public abstract class arrow/core/Option { public final fun getOrNull ()Ljava/lang/Object; public static final fun invoke (Ljava/lang/Object;)Larrow/core/Option; public final fun isDefined ()Z - public final fun isEmpty ()Z + public abstract fun isEmpty ()Z public final fun isNotEmpty ()Z public static final fun lift (Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function1; public final fun map (Lkotlin/jvm/functions/Function1;)Larrow/core/Option; @@ -1559,6 +1560,7 @@ public final class arrow/core/Some : arrow/core/Option { public fun equals (Ljava/lang/Object;)Z public final fun getValue ()Ljava/lang/Object; public fun hashCode ()I + public fun isEmpty ()Z public fun toString ()Ljava/lang/String; } From 8e8c09298173fd206b7830214e068c4c6b42cf12 Mon Sep 17 00:00:00 2001 From: franciscodr Date: Sat, 4 Feb 2023 21:28:31 +0100 Subject: [PATCH 09/25] Deprecate applicative/monad error methods --- .../commonMain/kotlin/arrow/core/Option.kt | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt index 319a84bde9d..5fa58ebe27c 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt @@ -1125,18 +1125,48 @@ public inline fun Option<*>.filterIsInstance(): Option = } } +@Deprecated( + NicheAPI + "Prefer using the orElse method", + ReplaceWith( + "orElse { Some(f(Unit)) }", + "arrow.core.Some", + "arrow.core.orElse" + ) +) public inline fun Option.handleError(f: (Unit) -> A): Option = handleErrorWith { Some(f(Unit)) } +@Deprecated( + NicheAPI + "Prefer using the orElse method", + ReplaceWith( + "orElse { f(Unit) }", + "arrow.core.orElse" + ) +) public inline fun Option.handleErrorWith(f: (Unit) -> Option): Option = if (isEmpty()) f(Unit) else this public fun Option>.flatten(): Option = flatMap(::identity) +@Deprecated( + NicheAPI + "Prefer using the Option DSL or explicit map with orElse", + ReplaceWith( + "map(fb).orElse { Some(fe(Unit)) }", + "arrow.core.Some", + "arrow.core.orElse" + ) +) public inline fun Option.redeem(fe: (Unit) -> B, fb: (A) -> B): Option = map(fb).handleError(fe) +@Deprecated( + NicheAPI + "Prefer using the Option DSL or explicit flatMap with orElse", + ReplaceWith( + "flatMap(fb).orElse(fe)", + "arrow.core.orElse" + ) +) public inline fun Option.redeemWith(fe: (Unit) -> Option, fb: (A) -> Option): Option = flatMap(fb).handleErrorWith(fe) @@ -1149,6 +1179,13 @@ public fun Option.replicate(n: Int, MA: Monoid): Option = MA.run { else map { a -> List(n) { a }.fold(empty()) { acc, v -> acc + v } } } +@Deprecated( + NicheAPI + "Prefer using the Option DSL or explicit flatmap", + ReplaceWith( + "flatMap { it.fold({ None }, { a -> Some(a) }) }", + "arrow.core.None", "arrow.core.Some" + ) +) public fun Option>.rethrow(): Option = flatMap { it.fold({ None }, { a -> Some(a) }) } From 78b43845022f663844ad0b24f07a39e053eec1cd Mon Sep 17 00:00:00 2001 From: franciscodr Date: Sun, 5 Feb 2023 17:00:04 +0100 Subject: [PATCH 10/25] Deprecate utility methods --- .../commonMain/kotlin/arrow/core/Option.kt | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt index 5fa58ebe27c..3726976355e 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt @@ -646,12 +646,20 @@ public sealed class Option { /** * alias for [isDefined] */ + @Deprecated( + "Duplicated API. Please use Option's member function isNotEmpty. This will be removed towards Arrow 2.0", + ReplaceWith("isNotEmpty()") + ) public fun nonEmpty(): Boolean = isDefined() /** * Returns true if the option is an instance of [Some], false otherwise. * @note Used only for performance instead of fold. */ + @Deprecated( + "Duplicated API. Please use Option's member function isNotEmpty. This will be removed towards Arrow 2.0", + ReplaceWith("isNotEmpty()") + ) public fun isDefined(): Boolean = !isEmpty() @Deprecated( @@ -704,6 +712,13 @@ public sealed class Option { * * @param f the function to apply. * */ + @Deprecated( + NicheAPI + "Prefer using the Option DSL, or fold or map", + ReplaceWith( + "flatMap { fromNullable(f(it)) }", + "arrow.core.Option.Companion.fromNullable" + ) + ) public inline fun mapNotNull(f: (A) -> B?): Option = flatMap { a -> fromNullable(f(a)) } @@ -1025,6 +1040,10 @@ public sealed class Option { ) public fun pairRight(right: R): Option> = this.map { it to right } + @Deprecated( + NicheAPI + "Prefer using the Option DSL or flatMap", + ReplaceWith("flatMap { value }") + ) public infix fun and(value: Option): Option = if (isEmpty()) { None } else { @@ -1072,14 +1091,33 @@ public inline fun Option.getOrElse(default: () -> T): T = fold({ default( public inline fun Option.orElse(alternative: () -> Option): Option = if (isEmpty()) alternative() else this +@Deprecated( + NicheAPI + "Prefer using the orElse method", + ReplaceWith("orElse(value)") +) public infix fun Option.or(value: Option): Option = if (isEmpty()) { value } else { this } +@Deprecated( + RedundantAPI + "Prefer using fromNullable", + ReplaceWith( + "Option.fromNullable(this)", + "arrow.core.Option" + ) +) public fun T?.toOption(): Option = this?.let { Some(it) } ?: None +@Deprecated( + NicheAPI + "Prefer using if-else statement", + ReplaceWith( + "if (this) { Some(f()) } else { None }", + "arrow.core.None", + "arrow.core.Some" + ) +) public inline fun Boolean.maybe(f: () -> A): Option = if (this) { Some(f()) @@ -1117,6 +1155,14 @@ public inline fun Option.ensure(error: () -> Unit, predicate: (A) -> Bool /** * Returns an Option containing all elements that are instances of specified type parameter [B]. */ +@Deprecated( + NicheAPI + "Prefer using option DSL or flatMap", + ReplaceWith( + "flatMap { when (it) { is B -> Some(it) else -> None } }", + "arrow.core.None", + "arrow.core.Some" + ) +) public inline fun Option<*>.filterIsInstance(): Option = flatMap { when (it) { From 356a273a2de61346a6c8ec31be6bda89b3dce468 Mon Sep 17 00:00:00 2001 From: franciscodr Date: Mon, 6 Feb 2023 12:26:56 +0100 Subject: [PATCH 11/25] Deprecate assign methods --- .../arrow-core/src/commonMain/kotlin/arrow/core/Option.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt index 047702cdeeb..6b7d2937acc 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt @@ -790,6 +790,7 @@ public sealed class Option { /** * Align two options (`this` on the left and [b] on the right) as one Option of [Ior]. */ + @Deprecated(NicheAPI + "Prefer using a simple fold, or when expression") public infix fun align(b: Option): Option> = when (this) { None -> when (b) { @@ -808,6 +809,7 @@ public sealed class Option { * * @note This function works like a regular `align` function, but is then mapped by the `map` function. */ + @Deprecated(NicheAPI + "Prefer using a simple fold, or when expression") public inline fun align(b: Option, f: (Ior) -> C): Option { contract { callsInPlace(f, InvocationKind.AT_MOST_ONCE) } return align(b).map(f) @@ -975,6 +977,7 @@ public sealed class Option { is None -> initial } + @Deprecated(NicheAPI + "Prefer using a simple fold, or when expression") public fun padZip(other: Option): Option> = align(other) { ior -> ior.fold( @@ -984,6 +987,7 @@ public sealed class Option { ) } + @Deprecated(NicheAPI + "Prefer using a simple fold, or when expression") public inline fun padZip(other: Option, f: (A?, B?) -> C): Option = align(other) { ior -> ior.fold( @@ -1333,6 +1337,7 @@ public fun Option.replicate(n: Int, MA: Monoid): Option = MA.run { public fun Option>.rethrow(): Option = flatMap { it.fold({ None }, { a -> Some(a) }) } +@Deprecated(NicheAPI + "Prefer using a simple fold, or when expression") public fun Option.salign(SA: Semigroup, b: Option): Option = align(b) { it.fold(::identity, ::identity) { a, b -> @@ -1430,9 +1435,11 @@ public fun Option>.sequenceValidated(): Validated Option>.sequence(): Validated> = traverse(::identity) +@Deprecated(NicheAPI + "Prefer using a when expression") public fun Option>.unalign(): Pair, Option> = unalign(::identity) +@Deprecated(NicheAPI + "Prefer using a when expression") public inline fun Option.unalign(f: (C) -> Ior): Pair, Option> = when (val option = this.map(f)) { is None -> None to None From 7fc257e7c05d82c7b30c689b767f3c62737ced65 Mon Sep 17 00:00:00 2001 From: franciscodr Date: Mon, 6 Feb 2023 12:51:17 +0100 Subject: [PATCH 12/25] Fix outdated knit files --- .../kotlin/examples/example-option-24.kt | 16 ++++++++-------- .../kotlin/examples/example-option-25.kt | 17 +++++++---------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-24.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-24.kt index dac69a1c753..9d49c2783b9 100644 --- a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-24.kt +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-24.kt @@ -1,14 +1,14 @@ // This file was automatically generated from Option.kt by Knit tool. Do not edit. package arrow.core.examples.exampleOption24 -import arrow.core.Option -import arrow.core.none import arrow.core.Some -import arrow.core.recover -import io.kotest.matchers.shouldBe +import arrow.core.None +import arrow.core.Option + +fun main() { + Some(12).exists { it > 10 } // Result: true + Some(7).exists { it > 10 } // Result: false -fun test() { - val error: Option = none() - val fallback: Option = error.recover { 5 } - fallback shouldBe Some(5) + val none: Option = None + none.exists { it > 10 } // Result: false } diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-25.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-25.kt index 791cc3dda5c..36d68d125c4 100644 --- a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-25.kt +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-25.kt @@ -1,17 +1,14 @@ // This file was automatically generated from Option.kt by Knit tool. Do not edit. package arrow.core.examples.exampleOption25 -import arrow.core.Option -import arrow.core.none import arrow.core.Some -import arrow.core.recover -import io.kotest.matchers.shouldBe +import arrow.core.None +import arrow.core.Option -fun test() { - val error: Option = none() - fun fallback(): Option = Some(5) - fun failure(): Option = none() +fun main() { + Some(12).exists { it > 10 } // Result: 12 + Some(7).exists { it > 10 } // Result: null - error.recover { fallback().bind() } shouldBe Some(5) - error.recover { failure().bind() } shouldBe none() + val none: Option = None + none.exists { it > 10 } // Result: null } From 8198fce10761500af02d10a97c22cb31eb29447d Mon Sep 17 00:00:00 2001 From: franciscodr Date: Mon, 6 Feb 2023 15:38:34 +0100 Subject: [PATCH 13/25] Using the inline option DSL --- .../commonMain/kotlin/arrow/core/Option.kt | 158 ++++++++++-------- 1 file changed, 84 insertions(+), 74 deletions(-) diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt index 6b7d2937acc..34de3a7db7d 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt @@ -397,41 +397,35 @@ public sealed class Option { public fun zip(other: Option): Option> = zip(other, ::Pair) + @Deprecated( + "Prefer using the inline option DSL", + ReplaceWith( + "option { map(bind(), b.bind()) }", + "arrow.core.raise.option" + ) + ) public inline fun zip( b: Option, map: (A, B) -> C ): Option { contract { callsInPlace(map, InvocationKind.AT_MOST_ONCE) } - return zip( - b, - Some.unit, - Some.unit, - Some.unit, - Some.unit, - Some.unit, - Some.unit, - Some.unit, - Some.unit - ) { b, c, _, _, _, _, _, _, _, _ -> map(b, c) } + return option { map(bind(), b.bind()) } } + @Deprecated( + "Prefer using the inline option DSL", + ReplaceWith( + "option { map(bind(), b.bind(), c.bind()) }", + "arrow.core.raise.option" + ) + ) public inline fun zip( b: Option, c: Option, map: (A, B, C) -> D ): Option { contract { callsInPlace(map, InvocationKind.AT_MOST_ONCE) } - return zip( - b, - c, - Some.unit, - Some.unit, - Some.unit, - Some.unit, - Some.unit, - Some.unit, - Some.unit - ) { b, c, d, _, _, _, _, _, _, _ -> map(b, c, d) } + return option { map(bind(), b.bind(), c.bind()) } } /** @@ -540,6 +534,13 @@ public sealed class Option { return onSome(f) } + @Deprecated( + "Prefer using the inline option DSL", + ReplaceWith( + "option { map(bind(), b.bind(), c.bind(), d.bind()) }", + "arrow.core.raise.option" + ) + ) public inline fun zip( b: Option, c: Option, @@ -547,19 +548,16 @@ public sealed class Option { map: (A, B, C, D) -> E ): Option { contract { callsInPlace(map, InvocationKind.AT_MOST_ONCE) } - return zip( - b, - c, - d, - Some.unit, - Some.unit, - Some.unit, - Some.unit, - Some.unit, - Some.unit - ) { a, b, c, d, _, _, _, _, _, _ -> map(a, b, c, d) } + return option { map(bind(), b.bind(), c.bind(), d.bind()) } } + @Deprecated( + "Prefer using the inline option DSL", + ReplaceWith( + "option { map(bind(), b.bind(), c.bind(), d.bind(), e.bind()) }", + "arrow.core.raise.option" + ) + ) public inline fun zip( b: Option, c: Option, @@ -568,17 +566,16 @@ public sealed class Option { map: (A, B, C, D, E) -> F ): Option { contract { callsInPlace(map, InvocationKind.AT_MOST_ONCE) } - return zip(b, c, d, e, Some.unit, Some.unit, Some.unit, Some.unit, Some.unit) { a, b, c, d, e, f, _, _, _, _ -> - map( - a, - b, - c, - d, - e - ) - } + return option { map(bind(), b.bind(), c.bind(), d.bind(), e.bind()) } } + @Deprecated( + "Prefer using the inline option DSL", + ReplaceWith( + "option { map(bind(), b.bind(), c.bind(), d.bind(), e.bind(), f.bind()) }", + "arrow.core.raise.option" + ) + ) public inline fun zip( b: Option, c: Option, @@ -588,18 +585,16 @@ public sealed class Option { map: (A, B, C, D, E, F) -> G ): Option { contract { callsInPlace(map, InvocationKind.AT_MOST_ONCE) } - return zip(b, c, d, e, f, Some.unit, Some.unit, Some.unit, Some.unit) { a, b, c, d, e, f, _, _, _, _ -> - map( - a, - b, - c, - d, - e, - f - ) - } + return option { map(bind(), b.bind(), c.bind(), d.bind(), e.bind(), f.bind()) } } + @Deprecated( + "Prefer using the inline option DSL", + ReplaceWith( + "option { map(bind(), b.bind(), c.bind(), d.bind(), e.bind(), f.bind(), g.bind()) }", + "arrow.core.raise.option" + ) + ) public inline fun zip( b: Option, c: Option, @@ -610,9 +605,16 @@ public sealed class Option { map: (A, B, C, D, E, F, G) -> H ): Option { contract { callsInPlace(map, InvocationKind.AT_MOST_ONCE) } - return zip(b, c, d, e, f, g, Some.unit, Some.unit, Some.unit) { a, b, c, d, e, f, g, _, _, _ -> map(a, b, c, d, e, f, g) } + return option { map(bind(), b.bind(), c.bind(), d.bind(), e.bind(), f.bind(), g.bind()) } } + @Deprecated( + "Prefer using the inline option DSL", + ReplaceWith( + "option { map(bind(), b.bind(), c.bind(), d.bind(), e.bind(), f.bind(), g.bind(), h.bind()) }", + "arrow.core.raise.option" + ) + ) public inline fun zip( b: Option, c: Option, @@ -624,9 +626,16 @@ public sealed class Option { map: (A, B, C, D, E, F, G, H) -> I ): Option { contract { callsInPlace(map, InvocationKind.AT_MOST_ONCE) } - return zip(b, c, d, e, f, g, h, Some.unit, Some.unit) { a, b, c, d, e, f, g, h, _, _ -> map(a, b, c, d, e, f, g, h) } + return option { map(bind(), b.bind(), c.bind(), d.bind(), e.bind(), f.bind(), g.bind(), h.bind()) } } + @Deprecated( + "Prefer using the inline option DSL", + ReplaceWith( + "option { map(bind(), b.bind(), c.bind(), d.bind(), e.bind(), f.bind(), g.bind(), h.bind(), i.bind()) }", + "arrow.core.raise.option" + ) + ) public inline fun zip( b: Option, c: Option, @@ -639,9 +648,16 @@ public sealed class Option { map: (A, B, C, D, E, F, G, H, I) -> J ): Option { contract { callsInPlace(map, InvocationKind.AT_MOST_ONCE) } - return zip(b, c, d, e, f, g, h, i, Some.unit) { a, b, c, d, e, f, g, h, i, _ -> map(a, b, c, d, e, f, g, h, i) } + return option { map(bind(), b.bind(), c.bind(), d.bind(), e.bind(), f.bind(), g.bind(), h.bind(), i.bind()) } } + @Deprecated( + "Prefer using the inline option DSL", + ReplaceWith( + "option { map(bind(), b.bind(), c.bind(), d.bind(), e.bind(), f.bind(), g.bind(), h.bind(), i.bind(), j.bind()) }", + "arrow.core.raise.option" + ) + ) public inline fun zip( b: Option, c: Option, @@ -655,11 +671,7 @@ public sealed class Option { map: (A, B, C, D, E, F, G, H, I, J) -> K ): Option { contract { callsInPlace(map, InvocationKind.AT_MOST_ONCE) } - return if (this is Some && b is Some && c is Some && d is Some && e is Some && f is Some && g is Some && h is Some && i is Some && j is Some) { - Some(map(this.value, b.value, c.value, d.value, e.value, f.value, g.value, h.value, i.value, j.value)) - } else { - None - } + return option { map(bind(), b.bind(), c.bind(), d.bind(), e.bind(), f.bind(), g.bind(), h.bind(), i.bind(), j.bind()) } } /** @@ -1262,26 +1274,25 @@ public inline fun Option<*>.filterIsInstance(): Option = @Deprecated( NicheAPI + "Prefer using the orElse method", ReplaceWith( - "orElse { Some(f(Unit)) }", - "arrow.core.Some", - "arrow.core.orElse" + "recover { f(Unit) }", + "arrow.core.recover" ) ) public inline fun Option.handleError(f: (Unit) -> A): Option { contract { callsInPlace(f, InvocationKind.AT_MOST_ONCE) } - return handleErrorWith { Some(f(Unit)) } + return recover { f(Unit) } } @Deprecated( NicheAPI + "Prefer using the orElse method", ReplaceWith( - "orElse { f(Unit) }", - "arrow.core.orElse" + "recover { f(Unit).bind() }", + "arrow.core.recover" ) ) public inline fun Option.handleErrorWith(f: (Unit) -> Option): Option { contract { callsInPlace(f, InvocationKind.AT_MOST_ONCE) } - return if (isEmpty()) f(Unit) else this + return recover { f(Unit).bind() } } public fun Option>.flatten(): Option = @@ -1290,9 +1301,8 @@ public fun Option>.flatten(): Option = @Deprecated( NicheAPI + "Prefer using the Option DSL or explicit map with orElse", ReplaceWith( - "map(fb).orElse { Some(fe(Unit)) }", - "arrow.core.Some", - "arrow.core.orElse" + "map(fb).recover { fe(Unit) }", + "arrow.core.recover" ) ) public inline fun Option.redeem(fe: (Unit) -> B, fb: (A) -> B): Option { @@ -1300,14 +1310,14 @@ public inline fun Option.redeem(fe: (Unit) -> B, fb: (A) -> B): Option callsInPlace(fe, InvocationKind.AT_MOST_ONCE) callsInPlace(fb, InvocationKind.AT_MOST_ONCE) } - return map(fb).handleError(fe) + return map(fb).recover { fe(Unit) } } @Deprecated( NicheAPI + "Prefer using the Option DSL or explicit flatMap with orElse", ReplaceWith( - "flatMap(fb).orElse(fe)", - "arrow.core.orElse" + "flatMap(fb).recover { fe(Unit).bind() }", + "arrow.core.recover" ) ) public inline fun Option.redeemWith(fe: (Unit) -> Option, fb: (A) -> Option): Option { @@ -1315,7 +1325,7 @@ public inline fun Option.redeemWith(fe: (Unit) -> Option, fb: (A) - callsInPlace(fe, InvocationKind.AT_MOST_ONCE) callsInPlace(fb, InvocationKind.AT_MOST_ONCE) } - return flatMap(fb).handleErrorWith(fe) + return flatMap(fb).recover { fe(Unit).bind() } } @Deprecated( From b0f9ff116e376815fedaee8fe77607b21df0940f Mon Sep 17 00:00:00 2001 From: franciscodr Date: Mon, 6 Feb 2023 20:05:53 +0100 Subject: [PATCH 14/25] Change redeem implementation for Either and Option --- .../arrow-core/src/commonMain/kotlin/arrow/core/Either.kt | 8 ++++---- .../arrow-core/src/commonMain/kotlin/arrow/core/Option.kt | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Either.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Either.kt index 258e493b3d4..9123816c3f8 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Either.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Either.kt @@ -2199,10 +2199,10 @@ public inline fun Either.handleError(f: (A) -> B): Either { } @Deprecated( - RedundantAPI + "Prefer the new recover API", + RedundantAPI + "Prefer using the Either DSL or explicit fold with right", ReplaceWith( - "map(fa).recover { a -> fe(a) }", - "arrow.core.recover" + "fold({ a -> fe(a) }, fa).right()", + "arrow.core.right" ) ) public inline fun Either.redeem(fe: (A) -> C, fa: (B) -> C): Either { @@ -2210,7 +2210,7 @@ public inline fun Either.redeem(fe: (A) -> C, fa: (B) -> C): Eit callsInPlace(fe, InvocationKind.AT_MOST_ONCE) callsInPlace(fa, InvocationKind.AT_MOST_ONCE) } - return map(fa).recover { a -> fe(a) } + return fold({ a -> fe(a) }, fa).right() } public operator fun , B : Comparable> Either.compareTo(other: Either): Int = diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt index 34de3a7db7d..7798f34ff4a 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt @@ -1299,10 +1299,10 @@ public fun Option>.flatten(): Option = flatMap(::identity) @Deprecated( - NicheAPI + "Prefer using the Option DSL or explicit map with orElse", + NicheAPI + "Prefer using the Option DSL or explicit fold with some", ReplaceWith( - "map(fb).recover { fe(Unit) }", - "arrow.core.recover" + "fold({ fe(Unit) }, fb).some()", + "arrow.core.some" ) ) public inline fun Option.redeem(fe: (Unit) -> B, fb: (A) -> B): Option { @@ -1310,7 +1310,7 @@ public inline fun Option.redeem(fe: (Unit) -> B, fb: (A) -> B): Option callsInPlace(fe, InvocationKind.AT_MOST_ONCE) callsInPlace(fb, InvocationKind.AT_MOST_ONCE) } - return map(fb).recover { fe(Unit) } + return fold({ fe(Unit) }, fb).some() } @Deprecated( From 49a018be1e696ca31fa16dd4e7b29fcd732c4c23 Mon Sep 17 00:00:00 2001 From: franciscodr Date: Tue, 7 Feb 2023 14:20:24 +0100 Subject: [PATCH 15/25] Fix wrong deprecation replacement --- .../arrow-core/src/commonMain/kotlin/arrow/core/Option.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt index 7798f34ff4a..532241c3a91 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt @@ -835,7 +835,7 @@ public sealed class Option { */ @Deprecated( NicheAPI + "Prefer using the Option DSL, or fold or map", - ReplaceWith("fold({ false }, predicate)") + ReplaceWith("fold({ true }, predicate)") ) public inline fun all(predicate: (A) -> Boolean): Boolean { contract { callsInPlace(predicate, InvocationKind.AT_MOST_ONCE) } @@ -931,7 +931,7 @@ public sealed class Option { */ @Deprecated( NicheAPI + "Prefer using the Option DSL, or fold or map", - ReplaceWith("fold({ true }, predicate)") + ReplaceWith("fold({ false }, predicate)") ) public inline fun exists(predicate: (A) -> Boolean): Boolean { contract { callsInPlace(predicate, InvocationKind.AT_MOST_ONCE) } From 58b51a4a130cb895351b51c53c0bd17a2fd02e47 Mon Sep 17 00:00:00 2001 From: franciscodr Date: Tue, 7 Feb 2023 14:20:54 +0100 Subject: [PATCH 16/25] Revert Nullable.toOption deprecation --- .../arrow-core/src/commonMain/kotlin/arrow/core/Option.kt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt index 532241c3a91..a937d3c43ab 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt @@ -1193,13 +1193,6 @@ public infix fun Option.or(value: Option): Option = if (isEmpty()) this } -@Deprecated( - RedundantAPI + "Prefer using fromNullable", - ReplaceWith( - "Option.fromNullable(this)", - "arrow.core.Option" - ) -) public fun T?.toOption(): Option = this?.let { Some(it) } ?: None @Deprecated( From 39366478599f00869d74e7448dfedde2b99b585b Mon Sep 17 00:00:00 2001 From: franciscodr Date: Tue, 7 Feb 2023 15:59:27 +0100 Subject: [PATCH 17/25] Add missing contracts --- .../commonMain/kotlin/arrow/core/Option.kt | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt index a937d3c43ab..0881fa33fe0 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt @@ -446,7 +446,6 @@ public sealed class Option { * ``` * */ - @OptIn(ExperimentalContracts::class) public inline fun onNone(action: () -> Unit): Option { contract { callsInPlace(action, InvocationKind.AT_MOST_ONCE) @@ -472,7 +471,6 @@ public sealed class Option { * ``` * */ - @OptIn(ExperimentalContracts::class) public inline fun onSome(action: (A) -> Unit): Option { contract { callsInPlace(action, InvocationKind.AT_MOST_ONCE) @@ -678,11 +676,19 @@ public sealed class Option { * Returns true if the option is [None], false otherwise. * @note Used only for performance instead of fold. */ - public abstract fun isEmpty(): Boolean + public fun isEmpty(): Boolean { + contract { + returns(false) implies (this@Option is Some) + returns(true) implies (this@Option is None) + } + return this@Option is None + } - @OptIn(ExperimentalContracts::class) public fun isNotEmpty(): Boolean { - contract { returns(true) implies (this@Option is Some) } + contract { + returns(true) implies (this@Option is Some) + returns(false) implies (this@Option is None) + } return this@Option is Some } @@ -732,7 +738,13 @@ public sealed class Option { * ``` * */ - public fun getOrNull(): A? = getOrElse { null } + public fun getOrNull(): A? { + contract { + returns(null) implies (this@Option is None) + returnsNotNull() implies (this@Option is Some) + } + return getOrElse { null } + } /** * Returns a [Some<$B>] containing the result of applying $f to this $option's @@ -1144,14 +1156,10 @@ public sealed class Option { } public object None : Option() { - public override fun isEmpty(): Boolean = true - override fun toString(): String = "Option.None" } public data class Some(val value: T) : Option() { - public override fun isEmpty(): Boolean = false - override fun toString(): String = "Option.Some($value)" public companion object { @@ -1226,7 +1234,11 @@ public fun Option.combineAll(MA: Monoid): A = @Deprecated( RedundantAPI + "Prefer if-else statement inside option DSL, or replace with explicit flatMap", - ReplaceWith("this.flatMap { b -> b.takeIf(predicate)?.let(::Some) ?: None.also(error) }") + ReplaceWith( + "this.flatMap { b -> b.takeIf(predicate)?.let(::Some) ?: None.also(error) }", + "arrow.core.Some", + "arrow.core.None" + ) ) public inline fun Option.ensure(error: () -> Unit, predicate: (A) -> Boolean): Option { contract { From 241d601528614ee7a1935c293db48885daea19c7 Mon Sep 17 00:00:00 2001 From: franciscodr Date: Tue, 7 Feb 2023 15:04:35 +0000 Subject: [PATCH 18/25] Update API files --- arrow-libs/core/arrow-core/api/arrow-core.api | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arrow-libs/core/arrow-core/api/arrow-core.api b/arrow-libs/core/arrow-core/api/arrow-core.api index b8e71668227..722ea8b1492 100644 --- a/arrow-libs/core/arrow-core/api/arrow-core.api +++ b/arrow-libs/core/arrow-core/api/arrow-core.api @@ -865,7 +865,6 @@ public final class arrow/core/NonFatalOrThrowKt { public final class arrow/core/None : arrow/core/Option { public static final field INSTANCE Larrow/core/None; - public fun isEmpty ()Z public fun toString ()Ljava/lang/String; } @@ -904,7 +903,7 @@ public abstract class arrow/core/Option { public final fun getOrNull ()Ljava/lang/Object; public static final fun invoke (Ljava/lang/Object;)Larrow/core/Option; public final fun isDefined ()Z - public abstract fun isEmpty ()Z + public final fun isEmpty ()Z public final fun isNotEmpty ()Z public static final fun lift (Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function1; public final fun map (Lkotlin/jvm/functions/Function1;)Larrow/core/Option; @@ -1593,7 +1592,6 @@ public final class arrow/core/Some : arrow/core/Option { public fun equals (Ljava/lang/Object;)Z public final fun getValue ()Ljava/lang/Object; public fun hashCode ()I - public fun isEmpty ()Z public fun toString ()Ljava/lang/String; } From d4f5bc41c23c7a80097df124536b6af205f075c3 Mon Sep 17 00:00:00 2001 From: franciscodr Date: Wed, 8 Feb 2023 15:22:33 +0100 Subject: [PATCH 19/25] Revert filterIsInstance deprecation --- .../arrow-core/src/commonMain/kotlin/arrow/core/Option.kt | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt index 0881fa33fe0..bcb69cddc5c 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt @@ -1260,14 +1260,6 @@ public inline fun Option.ensure(error: () -> Unit, predicate: (A) -> Bool /** * Returns an Option containing all elements that are instances of specified type parameter [B]. */ -@Deprecated( - NicheAPI + "Prefer using option DSL or flatMap", - ReplaceWith( - "flatMap { when (it) { is B -> Some(it) else -> None } }", - "arrow.core.None", - "arrow.core.Some" - ) -) public inline fun Option<*>.filterIsInstance(): Option = flatMap { when (it) { From df95be0ac6e1c277ea4fdf978b5e85f67231b44b Mon Sep 17 00:00:00 2001 From: franciscodr Date: Wed, 8 Feb 2023 22:23:31 +0100 Subject: [PATCH 20/25] Add isNone and isSome methods for Option --- .../commonMain/kotlin/arrow/core/Option.kt | 78 +++++++++++++++++-- .../kotlin/examples/example-option-26.kt | 11 +++ .../kotlin/examples/example-option-27.kt | 11 --- .../kotlin/examples/example-option-28.kt | 7 +- .../kotlin/examples/example-option-29.kt | 17 ++++ .../kotlin/examples/test/OptionKnitTest.kt | 8 +- 6 files changed, 105 insertions(+), 27 deletions(-) create mode 100644 arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-29.kt diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt index bcb69cddc5c..0c120dfa4b4 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt @@ -676,6 +676,10 @@ public sealed class Option { * Returns true if the option is [None], false otherwise. * @note Used only for performance instead of fold. */ + @Deprecated( + "Duplicated API. Please use Option's member function isNone. This will be removed towards Arrow 2.0", + ReplaceWith("isNone()") + ) public fun isEmpty(): Boolean { contract { returns(false) implies (this@Option is Some) @@ -684,6 +688,10 @@ public sealed class Option { return this@Option is None } + @Deprecated( + "Duplicated API. Please use Option's member function isSome. This will be removed towards Arrow 2.0", + ReplaceWith("isSome()") + ) public fun isNotEmpty(): Boolean { contract { returns(true) implies (this@Option is Some) @@ -692,12 +700,36 @@ public sealed class Option { return this@Option is Some } + /** + * Returns true if the option is [None], false otherwise. + * @note Used only for performance instead of fold. + */ + public fun isNone(): Boolean { + contract { + returns(false) implies (this@Option is Some) + returns(true) implies (this@Option is None) + } + return this@Option is None + } + + /** + * Returns true if the option is [Some], false otherwise. + * @note Used only for performance instead of fold. + */ + public fun isSome(): Boolean { + contract { + returns(true) implies (this@Option is Some) + returns(false) implies (this@Option is None) + } + return this@Option is Some + } + /** * alias for [isDefined] */ @Deprecated( - "Duplicated API. Please use Option's member function isNotEmpty. This will be removed towards Arrow 2.0", - ReplaceWith("isNotEmpty()") + "Duplicated API. Please use Option's member function isSome. This will be removed towards Arrow 2.0", + ReplaceWith("isSome()") ) public fun nonEmpty(): Boolean = isDefined() @@ -706,8 +738,8 @@ public sealed class Option { * @note Used only for performance instead of fold. */ @Deprecated( - "Duplicated API. Please use Option's member function isNotEmpty. This will be removed towards Arrow 2.0", - ReplaceWith("isNotEmpty()") + "Duplicated API. Please use Option's member function isSome. This will be removed towards Arrow 2.0", + ReplaceWith("isSome()") ) public fun isDefined(): Boolean = !isEmpty() @@ -1268,6 +1300,38 @@ public inline fun Option<*>.filterIsInstance(): Option = } } +/** + * Returns true if this option is nonempty '''and''' the predicate + * $p returns true when applied to this $option's value. + * Otherwise, returns false. + * + * Example: + * ```kotlin + * import arrow.core.Some + * import arrow.core.None + * import arrow.core.Option + * + * fun main() { + * Some(12).isSome { it > 10 } // Result: true + * Some(7).isSome { it > 10 } // Result: false + * + * val none: Option = None + * none.isSome { it > 10 } // Result: false + * } + * ``` + * + * + * @param predicate the predicate to test + */ +public inline fun Option.isSome(predicate: (A) -> Boolean): Boolean { + contract { + callsInPlace(predicate, InvocationKind.EXACTLY_ONCE) + returns(true) implies (this@isSome is Some) + returns(false) implies (this@isSome is None) + } + return this is Some && predicate(value) +} + @Deprecated( NicheAPI + "Prefer using the orElse method", ReplaceWith( @@ -1520,7 +1584,7 @@ public inline fun Option.unzip(f: (C) -> Pair): Pair + * */ public fun Option.widen(): Option = this @@ -1564,7 +1628,7 @@ public operator fun > Option.compareTo(other: Option): I * fallback shouldBe Some(5) * } * ``` - * + * * * * When shifting a new error [None] into the [Option]: @@ -1585,7 +1649,7 @@ public operator fun > Option.compareTo(other: Option): I * error.recover { failure().bind() } shouldBe none() * } * ``` - * + * * */ public inline fun Option.recover(recover: OptionRaise.(None) -> A): Option = diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-26.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-26.kt index d874951efa7..c2fbc6e0651 100644 --- a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-26.kt +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-26.kt @@ -1,3 +1,14 @@ // This file was automatically generated from Option.kt by Knit tool. Do not edit. package arrow.core.examples.exampleOption26 +import arrow.core.Some +import arrow.core.None +import arrow.core.Option + +fun main() { + Some(12).isSome { it > 10 } // Result: true + Some(7).isSome { it > 10 } // Result: false + + val none: Option = None + none.isSome { it > 10 } // Result: false +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-27.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-27.kt index a5d68877f12..5b54945e68a 100644 --- a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-27.kt +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-27.kt @@ -1,14 +1,3 @@ // This file was automatically generated from Option.kt by Knit tool. Do not edit. package arrow.core.examples.exampleOption27 -import arrow.core.Option -import arrow.core.none -import arrow.core.Some -import arrow.core.recover -import io.kotest.matchers.shouldBe - -fun test() { - val error: Option = none() - val fallback: Option = error.recover { 5 } - fallback shouldBe Some(5) -} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-28.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-28.kt index d56571a22f0..ba77029465d 100644 --- a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-28.kt +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-28.kt @@ -9,9 +9,6 @@ import io.kotest.matchers.shouldBe fun test() { val error: Option = none() - fun fallback(): Option = Some(5) - fun failure(): Option = none() - - error.recover { fallback().bind() } shouldBe Some(5) - error.recover { failure().bind() } shouldBe none() + val fallback: Option = error.recover { 5 } + fallback shouldBe Some(5) } diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-29.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-29.kt new file mode 100644 index 00000000000..227c8ef5ada --- /dev/null +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-29.kt @@ -0,0 +1,17 @@ +// This file was automatically generated from Option.kt by Knit tool. Do not edit. +package arrow.core.examples.exampleOption29 + +import arrow.core.Option +import arrow.core.none +import arrow.core.Some +import arrow.core.recover +import io.kotest.matchers.shouldBe + +fun test() { + val error: Option = none() + fun fallback(): Option = Some(5) + fun failure(): Option = none() + + error.recover { fallback().bind() } shouldBe Some(5) + error.recover { failure().bind() } shouldBe none() +} diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/test/OptionKnitTest.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/test/OptionKnitTest.kt index b85c303291b..1073ac2bc5d 100644 --- a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/test/OptionKnitTest.kt +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/test/OptionKnitTest.kt @@ -4,14 +4,14 @@ package arrow.core.examples.test import io.kotest.core.spec.style.StringSpec class OptionKnitTest : StringSpec({ - "ExampleOption27" { - arrow.core.examples.exampleOption27.test() - } - "ExampleOption28" { arrow.core.examples.exampleOption28.test() } + "ExampleOption29" { + arrow.core.examples.exampleOption29.test() + } + }) { override fun timeout(): Long = 1000 } From 6599bf3f4e4096129d7309e645151a34c680802d Mon Sep 17 00:00:00 2001 From: franciscodr Date: Wed, 8 Feb 2023 21:27:55 +0000 Subject: [PATCH 21/25] Update API files --- arrow-libs/core/arrow-core/api/arrow-core.api | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arrow-libs/core/arrow-core/api/arrow-core.api b/arrow-libs/core/arrow-core/api/arrow-core.api index c2774751b40..0ba3bf00eee 100644 --- a/arrow-libs/core/arrow-core/api/arrow-core.api +++ b/arrow-libs/core/arrow-core/api/arrow-core.api @@ -906,7 +906,9 @@ public abstract class arrow/core/Option { public static final fun invoke (Ljava/lang/Object;)Larrow/core/Option; public final fun isDefined ()Z public final fun isEmpty ()Z + public final fun isNone ()Z public final fun isNotEmpty ()Z + public final fun isSome ()Z public static final fun lift (Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function1; public final fun map (Lkotlin/jvm/functions/Function1;)Larrow/core/Option; public final fun mapNotNull (Lkotlin/jvm/functions/Function1;)Larrow/core/Option; @@ -964,6 +966,7 @@ public final class arrow/core/OptionKt { public static final fun getOrElse (Larrow/core/Option;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; public static final fun handleError (Larrow/core/Option;Lkotlin/jvm/functions/Function1;)Larrow/core/Option; public static final fun handleErrorWith (Larrow/core/Option;Lkotlin/jvm/functions/Function1;)Larrow/core/Option; + public static final fun isSome (Larrow/core/Option;Lkotlin/jvm/functions/Function1;)Z public static final fun maybe (ZLkotlin/jvm/functions/Function0;)Larrow/core/Option; public static final fun none ()Larrow/core/Option; public static final fun or (Larrow/core/Option;Larrow/core/Option;)Larrow/core/Option; From 6408a19e84495963a2c12f5a611e30dddd697c1f Mon Sep 17 00:00:00 2001 From: franciscodr Date: Thu, 9 Feb 2023 10:07:03 +0100 Subject: [PATCH 22/25] Trigger build From 4a9c1153704a1c544d06ec62682849b4b279a483 Mon Sep 17 00:00:00 2001 From: franciscodr Date: Thu, 9 Feb 2023 10:31:05 +0100 Subject: [PATCH 23/25] Update API files --- arrow-libs/core/arrow-core/api/arrow-core.api | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arrow-libs/core/arrow-core/api/arrow-core.api b/arrow-libs/core/arrow-core/api/arrow-core.api index 0ba3bf00eee..a49c85d58dc 100644 --- a/arrow-libs/core/arrow-core/api/arrow-core.api +++ b/arrow-libs/core/arrow-core/api/arrow-core.api @@ -909,6 +909,7 @@ public abstract class arrow/core/Option { public final fun isNone ()Z public final fun isNotEmpty ()Z public final fun isSome ()Z + public final fun isSome (Lkotlin/jvm/functions/Function1;)Z public static final fun lift (Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function1; public final fun map (Lkotlin/jvm/functions/Function1;)Larrow/core/Option; public final fun mapNotNull (Lkotlin/jvm/functions/Function1;)Larrow/core/Option; @@ -966,7 +967,6 @@ public final class arrow/core/OptionKt { public static final fun getOrElse (Larrow/core/Option;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; public static final fun handleError (Larrow/core/Option;Lkotlin/jvm/functions/Function1;)Larrow/core/Option; public static final fun handleErrorWith (Larrow/core/Option;Lkotlin/jvm/functions/Function1;)Larrow/core/Option; - public static final fun isSome (Larrow/core/Option;Lkotlin/jvm/functions/Function1;)Z public static final fun maybe (ZLkotlin/jvm/functions/Function0;)Larrow/core/Option; public static final fun none ()Larrow/core/Option; public static final fun or (Larrow/core/Option;Larrow/core/Option;)Larrow/core/Option; From 965395b19db343d29b7b97ffad89c2eb856851fb Mon Sep 17 00:00:00 2001 From: franciscodr Date: Thu, 9 Feb 2023 10:34:38 +0100 Subject: [PATCH 24/25] Convert isSome into an instance method --- .../commonMain/kotlin/arrow/core/Option.kt | 73 +++++++++---------- .../kotlin/examples/example-option-23.kt | 13 ++-- .../kotlin/examples/example-option-24.kt | 13 ++-- .../kotlin/examples/example-option-25.kt | 6 +- .../kotlin/examples/example-option-26.kt | 6 +- 5 files changed, 55 insertions(+), 56 deletions(-) diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt index 0c120dfa4b4..64b87177ceb 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt @@ -724,6 +724,37 @@ public sealed class Option { return this@Option is Some } + /** + * Returns true if this option is nonempty '''and''' the predicate + * $p returns true when applied to this $option's value. + * Otherwise, returns false. + * + * Example: + * ```kotlin + * import arrow.core.Some + * import arrow.core.None + * import arrow.core.Option + * + * fun main() { + * Some(12).isSome { it > 10 } // Result: true + * Some(7).isSome { it > 10 } // Result: false + * + * val none: Option = None + * none.isSome { it > 10 } // Result: false + * } + * ``` + * + * + * @param predicate the predicate to test + */ + public inline fun isSome(predicate: (A) -> Boolean): Boolean { + contract { + callsInPlace(predicate, InvocationKind.EXACTLY_ONCE) + returns(true) implies (this@Option is Some) + returns(false) implies (this@Option is None) + } + return this@Option is Some && predicate(value) + } /** * alias for [isDefined] */ @@ -768,7 +799,7 @@ public sealed class Option { * None.getOrNull() shouldBe null * } * ``` - * + * */ public fun getOrNull(): A? { contract { @@ -969,13 +1000,13 @@ public sealed class Option { * none.exists { it > 10 } // Result: false * } * ``` - * + * * * @param predicate the predicate to test */ @Deprecated( - NicheAPI + "Prefer using the Option DSL, or fold or map", - ReplaceWith("fold({ false }, predicate)") + RedundantAPI + "Please use Option's member function isSome. This will be removed towards Arrow 2.0", + ReplaceWith("isSome(predicate)") ) public inline fun exists(predicate: (A) -> Boolean): Boolean { contract { callsInPlace(predicate, InvocationKind.AT_MOST_ONCE) } @@ -1001,7 +1032,7 @@ public sealed class Option { * none.exists { it > 10 } // Result: null * } * ``` - * + * */ @Deprecated( NicheAPI + "Prefer Kotlin nullable syntax instead", @@ -1300,38 +1331,6 @@ public inline fun Option<*>.filterIsInstance(): Option = } } -/** - * Returns true if this option is nonempty '''and''' the predicate - * $p returns true when applied to this $option's value. - * Otherwise, returns false. - * - * Example: - * ```kotlin - * import arrow.core.Some - * import arrow.core.None - * import arrow.core.Option - * - * fun main() { - * Some(12).isSome { it > 10 } // Result: true - * Some(7).isSome { it > 10 } // Result: false - * - * val none: Option = None - * none.isSome { it > 10 } // Result: false - * } - * ``` - * - * - * @param predicate the predicate to test - */ -public inline fun Option.isSome(predicate: (A) -> Boolean): Boolean { - contract { - callsInPlace(predicate, InvocationKind.EXACTLY_ONCE) - returns(true) implies (this@isSome is Some) - returns(false) implies (this@isSome is None) - } - return this is Some && predicate(value) -} - @Deprecated( NicheAPI + "Prefer using the orElse method", ReplaceWith( diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-23.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-23.kt index f614536b8ef..fc55738f1ca 100644 --- a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-23.kt +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-23.kt @@ -1,11 +1,14 @@ // This file was automatically generated from Option.kt by Knit tool. Do not edit. package arrow.core.examples.exampleOption23 -import arrow.core.None import arrow.core.Some -import io.kotest.matchers.shouldBe +import arrow.core.None +import arrow.core.Option + +fun main() { + Some(12).isSome { it > 10 } // Result: true + Some(7).isSome { it > 10 } // Result: false -fun test() { - Some(12).getOrNull() shouldBe 12 - None.getOrNull() shouldBe null + val none: Option = None + none.isSome { it > 10 } // Result: false } diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-24.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-24.kt index 9d49c2783b9..8fa7b0b4bcd 100644 --- a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-24.kt +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-24.kt @@ -1,14 +1,11 @@ // This file was automatically generated from Option.kt by Knit tool. Do not edit. package arrow.core.examples.exampleOption24 -import arrow.core.Some import arrow.core.None -import arrow.core.Option - -fun main() { - Some(12).exists { it > 10 } // Result: true - Some(7).exists { it > 10 } // Result: false +import arrow.core.Some +import io.kotest.matchers.shouldBe - val none: Option = None - none.exists { it > 10 } // Result: false +fun test() { + Some(12).getOrNull() shouldBe 12 + None.getOrNull() shouldBe null } diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-25.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-25.kt index 36d68d125c4..7a2a5bce8ed 100644 --- a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-25.kt +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-25.kt @@ -6,9 +6,9 @@ import arrow.core.None import arrow.core.Option fun main() { - Some(12).exists { it > 10 } // Result: 12 - Some(7).exists { it > 10 } // Result: null + Some(12).exists { it > 10 } // Result: true + Some(7).exists { it > 10 } // Result: false val none: Option = None - none.exists { it > 10 } // Result: null + none.exists { it > 10 } // Result: false } diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-26.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-26.kt index c2fbc6e0651..8081a154033 100644 --- a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-26.kt +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-option-26.kt @@ -6,9 +6,9 @@ import arrow.core.None import arrow.core.Option fun main() { - Some(12).isSome { it > 10 } // Result: true - Some(7).isSome { it > 10 } // Result: false + Some(12).exists { it > 10 } // Result: 12 + Some(7).exists { it > 10 } // Result: null val none: Option = None - none.isSome { it > 10 } // Result: false + none.exists { it > 10 } // Result: null } From 3abcb1e4202bf56b7e8d9ea8dee9753d288d5f69 Mon Sep 17 00:00:00 2001 From: franciscodr Date: Thu, 9 Feb 2023 15:49:12 +0100 Subject: [PATCH 25/25] Restore abstract isEmpty function for Option --- arrow-libs/core/arrow-core/api/arrow-core.api | 4 +++- .../commonMain/kotlin/arrow/core/Option.kt | 20 ++++++++++++------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/arrow-libs/core/arrow-core/api/arrow-core.api b/arrow-libs/core/arrow-core/api/arrow-core.api index a49c85d58dc..dc651592283 100644 --- a/arrow-libs/core/arrow-core/api/arrow-core.api +++ b/arrow-libs/core/arrow-core/api/arrow-core.api @@ -867,6 +867,7 @@ public final class arrow/core/NonFatalOrThrowKt { public final class arrow/core/None : arrow/core/Option { public static final field INSTANCE Larrow/core/None; + public fun isEmpty ()Z public fun toString ()Ljava/lang/String; } @@ -905,7 +906,7 @@ public abstract class arrow/core/Option { public final fun getOrNull ()Ljava/lang/Object; public static final fun invoke (Ljava/lang/Object;)Larrow/core/Option; public final fun isDefined ()Z - public final fun isEmpty ()Z + public abstract fun isEmpty ()Z public final fun isNone ()Z public final fun isNotEmpty ()Z public final fun isSome ()Z @@ -1597,6 +1598,7 @@ public final class arrow/core/Some : arrow/core/Option { public fun equals (Ljava/lang/Object;)Z public final fun getValue ()Ljava/lang/Object; public fun hashCode ()I + public fun isEmpty ()Z public fun toString ()Ljava/lang/String; } diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt index 64b87177ceb..67a7854264f 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Option.kt @@ -680,13 +680,7 @@ public sealed class Option { "Duplicated API. Please use Option's member function isNone. This will be removed towards Arrow 2.0", ReplaceWith("isNone()") ) - public fun isEmpty(): Boolean { - contract { - returns(false) implies (this@Option is Some) - returns(true) implies (this@Option is None) - } - return this@Option is None - } + public abstract fun isEmpty(): Boolean @Deprecated( "Duplicated API. Please use Option's member function isSome. This will be removed towards Arrow 2.0", @@ -1219,10 +1213,22 @@ public sealed class Option { } public object None : Option() { + @Deprecated( + "Duplicated API. Please use Option's member function isNone. This will be removed towards Arrow 2.0", + replaceWith = ReplaceWith("isNone()") + ) + public override fun isEmpty(): Boolean = true + override fun toString(): String = "Option.None" } public data class Some(val value: T) : Option() { + @Deprecated( + "Duplicated API. Please use Option's member function isNone. This will be removed towards Arrow 2.0", + replaceWith = ReplaceWith("isNone()") + ) + public override fun isEmpty(): Boolean = false + override fun toString(): String = "Option.Some($value)" public companion object {