How can I check if a set of functions all return non null, in a single expression? - kotlin

Suppose I have three functions foo, bar, baz, all of which return nullable types.
fun foo(): Int? = 1
fun bar(): Int? = 2
fun baz(): Int? = 3
I want to call them, and if all them returns non-null, I want to compute a value from their return values.
I could do this with statements, like this:
val x = foo()
val y = bar()
val z = baz()
val result = if (x != null && y != null && z != null) x + y + z else null
However, I don't like the fact that I have to declare 3 extra variables that I can still access afterwards. By having 3 extra statements like this, it also means that I cannot use expression-bodied functions, if I were writing a function that returns result.
If I use lets instead:
val result = foo()?.let { x ->
bar()?.let { y ->
baz()?.let { z ->
x + y + z
}
}
}
This creates a deep nesting. If it were only one function, this would have been fine, but with 3 functions or more, this makes my intention of "call these three functions, if they are all non null, add them together" rather unclear.
How can I write this in a way that clearly conveys my intention, but also making it a single expression?

If they are of different types, I think you need to write your own helper functions like these (different overloads needed for different numbers of parameters, because there's no other way for the compiler to know the types of the arguments):
inline fun <T : Any, U : Any, R> ifAllNotNull(t: T?, u: U?, block: (t: T, u: U) -> R): R? {
return when {
t != null && u != null -> block(t, u)
else -> null
}
}
inline fun <T : Any, U : Any, V : Any, R> ifAllNotNull(t: T?, u: U?, v: V?, block: (t: T, u: U, v: V) -> R): R? {
return when {
t != null && u != null && v != null -> block(t, u, v)
else -> null
}
}
val result = ifAllNotNull(foo(), bar(), baz()) { x, y, z -> x + y + z }
Note that all three parameters will be evaluated before any are checked for null.
Or if you want to do what you described (hiding the three variables after the result calculation) using just standard library functions, you can use run to limit the scope of the temporary variables:
val result = run {
val x = foo()
val y = bar()
val z = baz()
if (x != null && y != null && z != null) x + y + z else null
}
This would also give you the opportunity to short-circuit if you like:
val result = run {
val x = foo() ?: return#run null
val y = bar() ?: return#run null
val z = baz() ?: return#run null
x + y + z
}

You could filter out all null-values and only apply an operation on the list, if it did not shrink in size, e.g.:
fun sumIfNoneNull(values: List<Int?>): Int? = values
.filterNotNull()
.takeIf { it.size == values.size }
?.sum()
One may generalize this further, e.g.:
fun <T, R> List<T>.foldIfNoneNull(
initial: R,
operation: (acc: R, T) -> R
): R? = this
.filterNotNull()
.takeIf { nonNullList -> nonNullList.size == this.size }
?.fold(initial, operation)
You may use this like any other fold, e.g.:
listOf(foo(), bar(), baz()).foldIfNoneNull(0) { acc, cur -> acc + cur }

val result = listOf(foo(), bar(), baz())
.reduce { acc, i ->
when {
acc == null || i == null -> null
else -> acc + i
}
}
Or as function:
fun <T> apply(operation: (T, T) -> T, vararg values: T?): T? {
return values
.reduce { acc, i ->
when {
acc == null || i == null -> null
else -> operation(acc, i)
}
}
}
val result = apply({ x, y -> x + y }, foo(), bar(), baz())

Related

How to explain implementation in Kotlin

I am really new in Kotlin programming language. I work with generic types and I found code statements shown below. What does it means? What is the meaning of each line?
class s(val b: t) : t by b {
fun f1(): Int = b.f3 + 1
override fun f2(g: Int): Any? = when {
g == 0 -> null
else -> b.f2(g - 1)
}
override fun l(g: Int, h: k?, z: m):
k = when {
g == 0 -> z.f1.f2.f3(1, z, true)
else -> b.l(g - 1, h, z)}}
override fun f4 (g: Int): Short = when {
g == 0 -> 0
else -> b.f4(g - 1)}}}

Where is the memoization?

I am learning Kotlin and from the book, I have the fibonacci function, that demonstrates memoization concept:
import java.math.BigInteger
fun <T> List<T>.head(): T =
if (this.isEmpty())
throw IllegalArgumentException("head called on empty list")
else
this[0]
fun <T> List<T>.tail(): List<T> =
if (this.isEmpty())
throw IllegalArgumentException("tail called on empty list")
else
this.subList(1, this.size)
fun <T, U> foldLeft(list: List<T>, z: U, f: (U, T) -> U): U {
tailrec fun foldLeft(list: List<T>, acc: U, f: (U, T) -> U): U =
if (list.isEmpty())
acc
else
foldLeft(list.tail(), f(acc, list.head()), f)
return foldLeft(list, z, f)
}
fun fibo(number: Int): String {
tailrec fun fibo(
acc: List<BigInteger>, acc1: BigInteger,
acc2: BigInteger, x: BigInteger
): List<BigInteger> =
when (x) {
BigInteger.ZERO -> acc
BigInteger.ONE -> acc + (acc1 + acc2)
else -> fibo(
acc + (acc1 + acc2), acc2, acc1 + acc2,
x - BigInteger.ONE
)
}
val list = fibo(
listOf(),
BigInteger.ONE, BigInteger.ZERO, BigInteger.valueOf(number.toLong())
)
return makeString(list, ", ")
}
fun <T> makeString(list: List<T>, separator: String): String =
when {
list.isEmpty() -> ""
list.tail().isEmpty() -> list.head().toString()
else -> list.head().toString() +
foldLeft(list.tail(), "") { x, y -> x + separator + y }
}
fun main(args: Array<String>) {
println(fibo(5))
}
Could someone explain it to me, where is memoization here?
I... don't think there is any, actually.
What I wanted to write initially is that the acc parameter of the helper fibo function (the one with 4 parameters marked by tailrec) ends up containing the previous Fibonacci numbers, but it isn't actually accessed to retrieve them, so I don't think it counts.
Here is what I would consider memoization in this style (note: I made x an Int because it simplifies code and you won't calculate a Fibonacci number with index not fitting into a Long in sane time even with memoization):
fun fibo(x: Int): BigInteger {
tailrec fun fibo(
acc: List<BigInteger>, x: Int
): Pair<List<BigInteger>, BigInteger> =
when {
x < acc.size -> Pair(acc, acc[x])
x == acc.size -> {
val y = acc[x - 1] + acc[x - 2]
Pair(acc + y, y)
}
else ->
fibo(fibo(fibo(acc, x - 2).first, x - 1).first, x)
}
return fibo(listOf(BigInteger.ONE, BigInteger.ONE), x).second
}
You can simplify it a bit and make memoization (think a memo/note to remind you of something. Sort of like a cache.) a bit more explicit by doing something like this:
fun fib(n: Int, memo: MutableMap<Int, BigInteger> = mutableMapOf()): BigInteger {
if (memo.containsKey(n)) return memo[n]!!
if (n <= 2) return BigInteger.ONE
memo[n] = fib(n - 1, memo) + fib(n - 2, memo)
return memo[n]!!
}
You can see memoization in action here as each iteration stores the position and value of each number in the sequence. And within each fib call, we first check to see if the value already exists before creating another node in the call stack (think of each subsequent recursive call as creating a set of branching nodes until n is 1 or 2).
This is lightning fast, yielding linear O(n) time and space complexity even for cases like finding the 1000th number in the sequence. As opposed to O(2^n) without memoization.
First saw algorithm here and ported to kotlin: https://youtu.be/oBt53YbR9Kk

How can I check 2 conditions using let (or apply etc)

Is there a more idiomatic way to write the following?
foo?.let{
if(!foo.isBlank()) {
bar?.let {
if(!bar.isBlank()) {
println("foo and bar both valid strings")
}
}
}
}
basically this the idea is that both strings should be nonNull and nonEmpty and I was wondering if there is a more Kotlin way than doing if(foo.isNullOrEmpty && !bar.isNullOrEmpty)
Use this
fun <T, R, S> biLet(lhs: T, rhs: R, block: (T, R) -> S): S? = if (lhs != null && rhs != null) block(lhs, rhs) else null
Use as
biLet(foo, bar) { safeFoo, safeBar ->
}
Edit: variant for strings
fun <T: CharSequence?, S> biLet(lhs: T, rhs: T, block: (T, T) -> S): S? =
if (lhs.isNotNullOrBlank() && rhs.isNotNullOrBlank()) block(lhs, rhs) else null
You can use sequenceOf and none:
if (sequenceOf(foo, bar).none { it.isNullOrBlank() }) {
println("foo and bar both valid strings")
}
Declare somewhere an extension function using lambdas like:
inline fun String.ifNotEmpty(bar: String, function: () -> Unit) {
if (this.isNotEmpty() && bar.isNotEmpty()) {
function.invoke()
}
}
And use it as:
val foo = "foo-value"
val bar = "bar-value"
foo.ifNotEmpty(bar) {
println("foo and bar both valid strings")
}
Improving #Francesc answer, I created a nLet version
fun <S> nLet(vararg ts: Any?, block: (Array<out Any?>) -> S): S? =
if (ts.none { when (it) { is String -> it.isNullOrEmpty() else -> it == null } }) block(ts) else null
You can use it like that
nLet (1, 2 , 3, "a", "B", true) { ts ->
ts.forEach { println(it) }
}
This is what I use:
fun <P1, P2, R> nLet(p1: P1?, p2: P2?, block: (P1, P2) -> R?): R? =
p1?.let { p2?.let { block(p1, p2) } }
Usage:
nLet(foo, bar) { f, b -> doStuff(f, b) }
Add more nLet functions with more P's if more arguments are needed.
You can also use this for an arbitary number of arguments:
fun <P, R> nLet(vararg ts: P?, block: (Array<out P?>) -> R): R? =
ts.takeIf { it.none { it == null } }?.let { block(it) }
Usage:
nLet(foo, bar, dog) { (f, b, d) -> doStuff(f, b, d) }
This works, but f, b and d will have nullable types even though they cannot be null.
(There might be a clever way to solve that...)

Kotlin equivalent for Optional::map in Java8

Do you know if there is a shortcut for:
if (x == null) null else f(x)
For Java Optional you can just do:
x.map(SomeClass::f)
Kotlin utilizes its own approach to the idea of Option, but there're map, filter, orElse equivalents:
val x: Int? = 7 // ofNullable()
val result = x
?.let(SomeClass.Companion::f) // map()
?.takeIf { it != 0 } // filter()
?: 42 // orElseGet()
I ended up writing a full comparison here:
You can use let in this case, like this:
fun f(x : Int) : Int{
return x+1
}
var x : Int? = 1
println(x?.let {f(it)} )
=> 2
x = null
println(x?.let {f(it)} )
=> null
and as #user2340612 mentioned, it is also the same to write:
println(x?.let(::f)
You can try with let (link to documentation):
x?.let(SomeClass::f)
Example
fun f(n: Int): Int {
return n+1
}
fun main(s: Array<String>) {
val n: Int? = null
val v: Int? = 3
println(n?.let(::f))
println(v?.let(::f))
}
This code prints:
null
4

Elementary functions in kotlin

Looking for a way to get elementary functions and their derivatives I approach it like this:
abstract class Fun() {
/**
* i = 0 -- the function itself,
* i = 1, 2, 3, ... -- its successive derivatives
*/
abstract fun d(i: Int, x: Float): Float
}
class Lin(val k: Float) : Fun() {
// y = k*x
override fun d(i: Int, x: Float, p: Float) = when (i) {
0 -> k * x
1 -> k
else -> 0.0f
}
}
class Sum(val fun0: Fun, val fun1: Fun) : Fun() {
// y = fun0(x) + fun1(x)
override fun d(i: Int, x: Float, p: Float) = fun0.d(i, x) + fun1.d(i, x)
}
class Example(val fun1: Fun, val fun2: Fun){
var res = fun1.d(0, 5.25f) // fun1 value at 5.25f
res = fun1.d(1, 3.29f) // fun1 first derivative at 3.29f
val sum = Sum(fun1, fun2) // sum of f1 and f2
res = sum(0, 3.78f) // sum value at 3.78f
res = sum(1, 5.69f) // sum first derivative at 5.69f
}
Is there a more idiomatic way to do it in Kotlin?
I have exposed the problem as I had done in Java, that is, classes that contain functions. My question is if I can do the same with functions, pass them on to a class like:
class ParametricCurveXYZ(val fun_x: Fun, val fun_y: Fun, val fun_z: Fun) {
fun pointToXYZ(s: Float) = VectorXYZ(fun_x.d(0, s), fun_y.d(0, s), fun_z.d(0, s))
fun tangent(s: Float) = VectorXYZ(fun_x.d(1, s), fun_y.d(1, s), fun_z.d(1, s)).normalized()
}
You can use lambdas instead of regular classes and overload operators to combine lambdas.
fun lin(k: Float) = { i: Int, x: Float ->
when (i) {
0 -> k * x
1 -> k
else -> 0.0f
}
}
operator fun ((Int, Float) -> Float).plus(that: (Int, Float) -> Float) =
{ i: Int, x: Float -> this(i, x) + that(i, x) }
fun doSomething() {
val sum = lin(1f) + lin(2f)
val res = sum(0, 3.78f)
}