Proposal for the Option/MayBe datatype


#1

Hello!

I took a look at Kotlin and it’s standard library recently and found a lack of the Option/MayBe datatype. It’s not so necessary in Kotlin as in other languages due to compile-time null checking but could have some usage: in my opinion, usage of map on the Option is more clear and concise than checking for null before applying function.

So my question to the Kotlin community and language authors:
Do you want to have a Option/MayBe type in the language standard library?

If the answer is “yes”, I’ll try to implement it, using Scala Option as a guideline for the API.


Java API design (for Kotlin consumption) ... Optional or null?
#2

Mario already has an implementation in his FunKtionale library you might want to look at...

https://github.com/MarioAriasC/funKTionale/tree/master/src/main/kotlin/org/funktionale/option


#3

Thank you.  I think another implementation is unnecessary, provided funKTionale is live and maintained.


#4

I took a look at Kotlin and it's standard library recently and found a lack of the Option/MayBe datatype. It's not so necessary in Kotlin as in other languages due to compile-time null checking but could have some usage: in my opinion, usage of map on the Option is more clear and concise than checking for null before applying function.

I'm a n00b in kotlin, but I'd say that Option is a bad idea for an language having also null. It leads to split where some libraries use Option and some use null. Moreover, sometimes you have to deal with nullable Option.

I can’t imagine a case where having Option leads to a better code. But as I said, I’m just a n00b and would love to get corrected.


#5

maaartinus wrote:

I’m a n00b in kotlin, but I’d say that Option is a bad idea for an language having also null. It leads to split where some libraries use Option and some use null. Moreover, sometimes you have to deal with nullable Option.

I don’t think so. For example, in Scala there are both null and Option but it seems to me that Option is predominant and null is used mostly for interoperation with Java. I’d rather say that null is a bad idea by itself. Kotlin goes to great lengths to make it less harmful but I still don’t like usage of null for representing absent optional value. Maybe, it’s inertia of my own mind.

,maaartinus wrote:

I can’t imagine a case where having Option leads to a better code. But as I said, I’m just a n00b and would love to get corrected.


It’s matter of taste, of course. But for me

mayBeValue map doSmth

or

mayBeValue forEach doSmth

is more concise than

if (mayBeValue != null) doSmth(mayBeValue)


In the case of multiple values it’s depends on the additional language features.
The code

mayBeA flatMap { a ->
  mayBeB flatMap { b ->
  mayBeC map { c ->
  doSmth(a, b, c)
  }
  }
}

probably, not more readable than

if ((mayBeA != null) && (mayBeB != null) && (mayBeC != null)) {
  doSmth(a, b, c)
}

but

for {
a <- mayBeA
b <- mayBeB
c <- mayBeC
} yield doSmth(a, b, c)

is (for me, at least).


#6

I'm a n00b in kotlin, but I'd say that Option is a bad idea for an language having also null. It leads to split where some libraries use Option and some use null. Moreover, sometimes you have to deal with nullable Option.

I don't think so. For example, in Scala there are both null and Option but it seems to me that Option is predominant and null is used mostly for interoperation with Java. I'd rather say that null is a bad idea by itself. Kotlin goes to great lengths to make it less harmful but I still don't like usage of null for representing absent optional value. Maybe, it's inertia of my own mind.

I believe that it's all just a matter of proper language syntax and library support. Option<T> may have a value or not. T? may have a value or not. Can you spot the difference? I can't.

It's matter of taste, of course. But for me

mayBeValue map doSmth

or

mayBeValue forEach doSmth

is more concise than

``

if (mayBeValue != null) doSmth(mayBeValue)

There's no reason to write such complicated things. Even I was able to write this:

import java.util.ArrayList public inline fun <T, R> List<out T>?.myMap(transform: (T) -> R): List<R>? {   if (this==null) return null;   return myMapTo(ArrayList<R>(), transform) } public inline fun <T, R, C : MutableCollection<in R>> List<out T>?.myMapTo(destination: C, transform: (T) -> R): C? {   if (this!=null) {   for (item in this) destination.add(transform(item))   }   return destination } val nullList :List<String>? = null val normalList :List<String>? = listOf("a", "b") fun doSmth(s: String) : String = "$s$s" fun main(args: Array<String>) {

  println(normalList myMap ::doSmth)   println(nullList myMap ::doSmth)

}
I had to define my own null-accepting myMap and use a different name for it. Does anybody know
  • why the standard map doesn't accept null?
  • why I can't overload on T and T?

I’d bet it’s possible to do the same for flatMap, too, why shouldn’t it?


#7

I don't think that something like Optional should be part of a third party library. If it is a supported concept, it should be part of the Kotlin standard library so that all other libraries can use the data type and leverage it for their own APIs. It would be nice if it played nicely together with Java's version of Optional.


#8

I don't mind the idea of Open/Maybe type, although I think it is already availabe in Kotlin because of the nullable types already making it clear what is optional or not.  But, I would never like to see this forced to be used from things like myMap.get("key") since you then have to always dereference.  Extensions can have myMap.getOptional("key") but let's not break the closeness to the Java built-in collection classes.

I find that there are patterns I use now that make me not even think about Optional very often.  For example:


  myMap.ifContains(“key”) { value -> … do something … }
  myMap.ifNotContains(“key”) { … do something else … }

and variations that deal with what present means (null, empty string, empty string once trimmed).

These extensions make my code clearer what I intend anyway than guessing from the if statements (does each if statement really need null check, trim().isNotEmpty()?).  You can also extend to create patterns like:

  val myMap = mapOf(“one” to 1, “two” to 2)
  myMap.ifContains(“one”) {  value ->
  println(value)
  } otherwise {
  println(“not found”)
  }

Or maybe that is backwards for reading and we are extending the wrong thing.  String could be extended to get the words in the right order (for English sentences):

  “one”.isPresentIn(myMap) {  value ->
  println(value)
  } otherwise {
  println(“not found”)
  }

Outside of this use case, I also have patterns like “add a default, but let me know you used the default” where I have data classes like:

  data class PropertyValue(val value: String, val wasDefaulted: Boolean)

And then my property class would have a few varations of getting properties:

  props.getValue(“forProperty”) -> String
  props.getValueElse(“forProperty”) { … generate default … } -> String
  props.getValueElse(“forProperty”, “literalDefault”) -> String
  props.getValueDefaulted(“forProperty”) { … generate default … } -> PropertyValue
  props.getValueDefaulted(“forProperty”, “literalDefault”) -> PropertyValue

No optional needed, and it is clearer for this case than a generic Optional would be.  And I can avoid the new return class if it doesn’t make sense at the call site (sometimes I don’t care if it was defaulted, other times I need to know).

More ways to skin the cat…  

  


#9

+1


#10

I don't think that something like Optional should be part of a third party library. If it is a supported concept, it should be part of the Kotlin standard library so that all other libraries can use the data type and leverage it for their own APIs.

I don’t think, something like this should ever exist in an language having also nulls. The more it gets used, the worse, as it creates more and more library inconsistencies.

IMHO Java Optional is just library sweetener substituting lacking language sugar. Kotlin has this sugar.

I might be wrong, but then please anyone show me what can be done with Optional and not with nulls (see my example below).


#11

Looking at things the other way around: would it be a good idea if Kotlin treated Java's Optional type as ?

public Optional<String> doStuff(Optional<Integer> someInput)

would be treated by Kotlin as

public fun doStuff(Int? someInput): String?

There would probably need to be some magic going on behind the scenes to make something like that possible and I am wondering that would be something worth having?


#12

I see no point in polluting the language with the Option type, when the same feature is achieved at a language-level with explicit nullable types :-)

  val x : String? = getSomeString()

- String? is equivalent to an Optional<String> - Optional.getOrElse() is already there as the default ":?" operator

   val y: String = x :? "default value"

- Optional.map( (T) -> T ) is equivalent to the safe navigation operator ".?"

e.g.:

   //Optional<String> x
   x.map( x -> x.length() )

which maps x into Option<Integer> when x is not None, and maps it into None when it s

is exactly the same as

   val x: Int? = x?.length()

and so on.