3

Let's imagine you have 2 fonctions returning nullable and you cant to compose this 2 functions :

fun giveInt(x: Int):Int? = x+1
fun giveInt2(x: Int):Int? = x+2

To achieve the composition, I wrote this functions :

fun all(x:Int):Int? {
  val y = giveInt(x)
  if (y != null) return giveInt2(y) else return null;
}

val four = all(1)

Is it possible to compose 2 nullable values to get another nullable without explicitly writing if (y != null) and return null?

In Scala I would just do something like :

def giveInt(x: Int):Option[Int] = Some(x+1)
def giveInt2(x: Int):Option[Int] = Some(x+2)
def all(x:Int): Option[Int] = giveInt(x).flatMap(giveInt2)

Should I use java Optional to achieve this or is it possible with ? operator?

Thanks :)

Loic
  • 3,310
  • 4
  • 25
  • 43
  • 1
    This is heavily covered by: http://stackoverflow.com/questions/34498562/in-kotlin-what-is-the-idiomatic-way-to-deal-with-nullable-values-referencing-o – Jayson Minard May 18 '16 at 00:14

3 Answers3

6

It is possible with safe call ?. operator and let function combo like this:

fun giveInt(x: Int):Int? = x+1
fun giveInt2(x: Int):Int? = x+2

fun all(x: Int): Int? = giveInt(x)?.let { giveInt2(it) }

For more idioms like this, use this link.

erkangur
  • 2,048
  • 5
  • 21
  • 31
3

In case you want to literally compose two functions (in the FP sense), then it is better to use function references for readability:

fun giveInt(x: Int):Int? = x+1
fun giveInt2(x: Int):Int? = x+2

fun all(x: Int): Int? = giveInt(x)?.let(::giveInt2)
voddan
  • 31,956
  • 8
  • 77
  • 87
0

the answer of voddan is ok when you have only two nullables, but doesn't scale well on many nullables or in complicated use-case. For these situations there exist Konad library that handles multiple nullables as follows:

val foo: Int? = 1
val bar: String? = "2"
val baz: Float? = 3.0f

fun useThem(x: Int, y: String, z: Float): Int = x + y.toInt() + z.toInt()

val result: Int? = ::useThem.curry() 
   .on(foo.maybe) 
   .on(bar.maybe) 
   .on(baz.maybe)
   .nullable

if you want to keep it nullable, or

val result: Result<Int> = ::useThem.curry() 
   .on(foo.ifNull("Foo should not be null")) 
   .on(bar.ifNull("Bar should not be null")) 
   .on(baz.ifNull("Baz should not be null"))
   .result

if you want to accumulate errors. See maybe section

Dharman
  • 30,962
  • 25
  • 85
  • 135
Luca Piccinelli
  • 379
  • 1
  • 17