Extension Function: Object.map


#1

Kotlin being null safe is great. However, I miss a function on Object that allows me to perform a null-safe transform. In Java, you would do:

Optional.ofNullable(obj).map(obj-> transform(obj)).orElse(null)

… which is rather lengthy and really inconventient. However, to the best of my knowledge, there is no method in the standard library of Kotlin that allows us to do this for nullable types. Of course, one can define an extension function:

fun <T, U> T?.map(transform: (T) -> U): U? {
    return if(this == null) null else transform(this)
}

… however, this extension function tends to conflict a lot, in particular with Collection#map and Optional#map (which is clearly unintended). I still can’t think of a better name that would avoid these collisions.

As an aside, if the transform function is a method of the object, one can do obj.?transform() to achieve the same thing, but that doesn’t work if transform is an arbitrary function or lambda.

What do you guys think about this?


#2

How does the following suite your needs?

val names: List<String>? = listOf("potato", "tomato")
val newNames = names?.let { name -> name.map { it.toLowerCase() } }

newNames will be null if names is null, otherwise it’ll map as expected.

Specifically to your example:

Optional.ofNullable(obj).map(obj-> transform(obj)).orElse(null)

would translate to:

obj?.let { obj -> transform(obj) }

#3

Note: T? is the same as T in your example, because you did not specify an upper bound for T. The default is Any?.

You can use either let or run:

obj?.let { /* Do something with "it" and return a result. */ }
obj?.let { theObj -> /* Do something with "theObj" and return a result. */ }
obj?.run { /* Do something with "this" and return a result. */ }

#4

Yeah, let is a nice solution. I didn’t realize that let actually returns something. It’s a bit less clear when reading than map (because that is actually what you do on the semantic level), but it does the trick :slight_smile:


#5

Glad to hear it!

You can always write an extension function as sort of an alias if you prefer a different word, but obviously using map specifically will result in some possible collisions you were referring to in the OP.


#6

See also my post on medium regarding this:

“Kotlin Nullable Types vs. Java Optional” https://medium.com/@fatihcoskun/kotlin-nullable-types-vs-java-optional-988c50853692

Especially section ‘Optional.map() vs. let() Function’.