arrow-core-data / arrow.core / Option

Option

@higherkind sealed class Option<out A>

beginner

If you have worked with Java at all in the past, it is very likely that you have come across a NullPointerException at some time (other languages will throw similarly named errors in such a case). Usually this happens because some method returns null when you were not expecting it and thus not dealing with that possibility in your client code. A value of null is often abused to represent an absent optional value. Kotlin tries to solve the problem by getting rid of null values altogether and providing its own special syntax Null-safety machinery based on ?.

Arrow models the absence of values through the Option datatype similar to how Scala, Haskell and other FP languages handle optional values.

Option<A> is a container for an optional value of type A. If the value of type A is present, the Option<A> is an instance of Some<A>, containing the present value of type A. If the value is absent, the Option<A> is the object None.


import arrow.core.Option
import arrow.core.Some
import arrow.core.none

//sampleStart
val someValue: Option<String> = Some("I am wrapped in something")
val emptyValue: Option<String> = none()
//sampleEnd
fun main() {
 println("value = $someValue")
 println("emptyValue = $emptyValue")
}

Let’s write a function that may or not give us a string, thus returning Option<String>:


import arrow.core.None
import arrow.core.Option
import arrow.core.Some

//sampleStart
fun maybeItWillReturnSomething(flag: Boolean): Option<String> =
 if (flag) Some("Found value") else None
//sampleEnd

Using getOrElse we can provide a default value "No value" when the optional argument None does not exist:


import arrow.core.None
import arrow.core.Option
import arrow.core.Some
import arrow.core.getOrElse

fun maybeItWillReturnSomething(flag: Boolean): Option<String> =
 if (flag) Some("Found value") else None

val value1 =
//sampleStart
 maybeItWillReturnSomething(true)
    .getOrElse { "No value" }
//sampleEnd
fun main() {
 println(value1)
}

import arrow.core.None
import arrow.core.Option
import arrow.core.Some
import arrow.core.getOrElse

fun maybeItWillReturnSomething(flag: Boolean): Option<String> =
 if (flag) Some("Found value") else None

val value2 =
//sampleStart
 maybeItWillReturnSomething(false)
  .getOrElse { "No value" }
//sampleEnd
fun main() {
 println(value2)
}

Checking whether option has value:


import arrow.core.None
import arrow.core.Option
import arrow.core.Some

fun maybeItWillReturnSomething(flag: Boolean): Option<String> =
 if (flag) Some("Found value") else None

 //sampleStart
val valueSome = maybeItWillReturnSomething(true) is None
val valueNone = maybeItWillReturnSomething(false) is None
//sampleEnd
fun main() {
 println("valueSome = $valueSome")
 println("valueNone = $valueNone")
}

Creating a Option<T> of a T?. Useful for working with values that can be nullable:


import arrow.core.Option


//sampleStart
val myString: String? = "Nullable string"
val option: Option<String> = Option.fromNullable(myString)
//sampleEnd
fun main () {
 println("option = $option")
}

Option can also be used with when statements:


import arrow.core.None
import arrow.core.Option
import arrow.core.Some

//sampleStart
val someValue: Option<Double> = Some(20.0)
val value = when(someValue) {
 is Some -> someValue.t
 is None -> 0.0
}
//sampleEnd
fun main () {
 println("value = $value")
}

import arrow.core.None
import arrow.core.Option
import arrow.core.Some

//sampleStart
val noValue: Option<Double> = None
val value = when(noValue) {
 is Some -> noValue.t
 is None -> 0.0
}
//sampleEnd
fun main () {
 println("value = $value")
}

An alternative for pattern matching is performing Functor/Foldable style operations. This is possible because an option could be looked at as a collection or foldable structure with either one or zero elements.

One of these operations is map. This operation allows us to map the inner value to a different type while preserving the option:


import arrow.core.None
import arrow.core.Option
import arrow.core.Some

//sampleStart
val number: Option<Int> = Some(3)
val noNumber: Option<Int> = None
val mappedResult1 = number.map { it * 1.5 }
val mappedResult2 = noNumber.map { it * 1.5 }
//sampleEnd
fun main () {
 println("number = $number")
 println("noNumber = $noNumber")
 println("mappedResult1 = $mappedResult1")
 println("mappedResult2 = $mappedResult2")
}

Another operation is fold. This operation will extract the value from the option, or provide a default if the value is None


import arrow.core.Option
import arrow.core.Some

val fold =
//sampleStart
 Some(3).fold({ 1 }, { it * 3 })
//sampleEnd
fun main () {
 println(fold)
}

import arrow.core.Option
import arrow.core.none

val fold =
//sampleStart
 none<Int>().fold({ 1 }, { it * 3 })
//sampleEnd
fun main () {
 println(fold)
}

Arrow also adds syntax to all datatypes so you can easily lift them into the context of Option where needed.


import arrow.core.some

//sampleStart
 val some = 1.some()
 val none = none<String>()
//sampleEnd
fun main () {
 println("some = $some")
 println("none = $none")
}

import arrow.core.toOption

//sampleStart
val nullString: String? = null
val valueFromNull = nullString.toOption()

val helloString: String? = "Hello"
val valueFromStr = helloString.toOption()
//sampleEnd
fun main () {
 println("valueFromNull = $valueFromNull")
 println("valueFromStr = $valueFromStr")
}

Some Iterable extensions are available, so you can maintain a friendly API syntax while avoiding null handling (firstOrNull())


import arrow.core.firstOrNone

//sampleStart
val myList: List<Int> = listOf(1,2,3,4)

val first4 = myList.firstOrNone { it == 4 }
val first5 = myList.firstOrNone { it == 5 }
//sampleEnd
fun main () {
 println("first4 = $first4")
 println("first5 = $first5")
}

Sample usage


import arrow.core.firstOrNone
import arrow.core.toOption

//sampleStart
val foxMap = mapOf(1 to "The", 2 to "Quick", 3 to "Brown", 4 to "Fox")

val ugly = foxMap.entries.firstOrNull { it.key == 5 }?.value.let { it?.toCharArray() }.toOption()
val pretty = foxMap.entries.firstOrNone { it.key == 5 }.map { it.value.toCharArray() }
//sampleEnd
fun main() {
 println("ugly = $ugly")
 println("pretty = $pretty")
}

Arrow contains Option instances for many useful typeclasses that allows you to use and transform optional values

Functor

Transforming the inner contents


import arrow.core.Some

fun main() {
val value =
 //sampleStart
   Some(1).map { it + 1 }
 //sampleEnd
 println(value)
}

Applicative

Computing over independent values


import arrow.core.Some
import arrow.core.extensions.option.apply.tupled

 val value =
//sampleStart
 tupled(Some(1), Some("Hello"), Some(20.0))
//sampleEnd
fun main() {
 println(value)
}

Monad

Computing over dependent values ignoring absence


import arrow.core.extensions.fx
import arrow.core.Some
import arrow.core.Option

val value =
//sampleStart
 Option.fx {
 val (a) = Some(1)
 val (b) = Some(1 + a)
 val (c) = Some(1 + b)
 a + b + c
}
//sampleEnd
fun main() {
 println(value)
}

import arrow.core.extensions.fx
import arrow.core.Some
import arrow.core.none
import arrow.core.Option

val value =
//sampleStart
 Option.fx {
   val (x) = none<Int>()
   val (y) = Some(1 + x)
   val (z) = Some(1 + y)
   x + y + z
 }
//sampleEnd
fun main() {
 println(value)
}

Supported type classes

Module Type classes
arrow.aql Count, From, GroupBy, Max, Min, OrderBy, Select, Sum, Union, Where
arrow.optics.typeclasses Each
arrow.recursion.typeclasses Birecursive, Corecursive, Recursive
arrow.typeclasses Alternative, Applicative, ApplicativeError, Apply, Eq, Foldable, Functor, FunctorFilter, Hash, Monad, MonadCombine, MonadError, MonadFilter, Monoid, MonoidK, Monoidal, Selective, Semigroup, SemigroupK, Semigroupal, Semiring, Show, Traverse, TraverseFilter

Credits

Contents partially adapted from Scala Exercises Option Tutorial Originally based on the Scala Koans.

Functions

and infix fun <X> and(value: Option<X>): Option<X>
ap fun <B> ap(ff: <ERROR CLASS><(A) -> B>): Option<B>
exists Returns true if this option is nonempty ‘'’and’’’ the predicate $p returns true when applied to this $option’s value. Otherwise, returns false.fun exists(predicate: Predicate<A>): Boolean
filter Returns this $option if it is nonempty ‘'’and’’’ applying the predicate $p to this $option’s value returns true. Otherwise, return $none.fun filter(predicate: Predicate<A>): Option<A>
filterMap fun <B> filterMap(f: (A) -> Option<B>): Option<B>
filterNot Returns this $option if it is nonempty ‘'’and’’’ applying the predicate $p to this $option’s value returns false. Otherwise, return $none.fun filterNot(predicate: Predicate<A>): Option<A>
flatMap Returns the result of applying $f to this $option’s value if this $option is nonempty. Returns $none if this $option is empty. Slightly different from map in that $f is expected to return an $option (which could be $none).fun <B> flatMap(f: (A) -> <ERROR CLASS><B>): Option<B>
fold fun <R> fold(ifEmpty: () -> R, ifSome: (A) -> R): R
foldLeft fun <B> foldLeft(initial: B, operation: (B, A) -> B): B
foldRight fun <B> foldRight(initial: Eval<B>, operation: (A, Eval<B>) -> Eval<B>): Eval<B>
forall Returns true if this option is empty ‘'’or’’’ the predicate $p returns true when applied to this $option’s value.fun forall(p: Predicate<A>): Boolean
isDefined Returns true if the option is an instance of Some, false otherwise.fun isDefined(): Boolean
isEmpty Returns true if the option is None, false otherwise.abstract fun isEmpty(): Boolean
map Returns a Some$B containing the result of applying $f to this $option’s value if this $option is nonempty. Otherwise return $none.fun <B> map(f: (A) -> B): Option<B>
map2 fun <B, R> map2(fb: Kind<<ERROR CLASS>, B>, f: (Tuple2<A, B>) -> R): Option<R>
mapNotNull Returns $none if the result of applying $f to this $option’s value is null. Otherwise returns the result.fun <B> mapNotNull(f: (A) -> B?): Option<B>
nonEmpty alias for isDefinedfun nonEmpty(): Boolean
orNull fun orNull(): A?
toEither fun <L> toEither(ifEmpty: () -> L): Either<L, A>
toList fun toList(): List<A>

Companion Object Functions

empty fun <A> empty(): Option<A>
fromNullable fun <A> fromNullable(a: A?): Option<A>
invoke operator fun <A> invoke(a: A): Option<A>
just Lifts a pure A value to Optionfun <A> just(a: A): Option<A>
tailRecM tailrec fun <A, B> tailRecM(a: A, f: (A) -> <ERROR CLASS><Either<A, B>>): Option<B>

Extension Functions

getOrElse Returns the option’s value if the option is nonempty, otherwise return the result of evaluating default.fun <T> Option<T>.getOrElse(default: () -> T): T
k fun <K, A> Option<Tuple2<K, A>>.k(): MapK<K, A>
fun <A : Comparable<A>, B> Option<Tuple2<A, B>>.k(): SortedMapK<A, B>
select fun <A, B> Option<Either<A, B>>.select(f: <ERROR CLASS><(A) -> B>): Option<B>

Inheritors

None object None : Option<Nothing>
Some data class Some<out T> : Option<T>

Type Class Hierarchy