Kotlin infix function with generics - kotlin

Try to write a simple Kotlin infix function for plus operation. What's wrong with generic type?
infix fun <T : Number> T.myPlus(that: T): T = this + that

As others have mentioned, there's no solutions using generics for various reasons. You have to define an extension function for each Number type (Byte, Short, Int, Long, Float, Double). E.g. for Int you could do:
when (that) {
is Byte, is Short, is Int, is Long -> that.toLong().plus(this)
is Float -> that + this
is Double -> that + this
else -> throw Exception("Types mismatch")
}
Even doing that, in some cases you need to decide whether you want to truncate or round the result.
val n1 = 1230000000000000000L
val n2 = 123.7
This case (n1 is a Long, n2 is a Float) could be handled like this:
is Float -> this + that.toLong()
resulting in 1230000000000000123
or it could be handled like this:
is Float -> this.toFloat() + that
resulting in 1.23E18

You forgot the operator keyword:
infix operator fun T.plus(that: T): T = this + that
Edit:
infix fun Number.infixPlus(that: Number): Number =
when (that) {
is Int -> this.toInt() + that
is Long -> this.toLong() + that
is Float -> this.toFloat() + that
is Double -> this.toDouble() + that
else -> throw Exception()
}
val n1 = 123
val n2 = 123.456
val result = n1 infixPlus n2
println("result: " + result)
println("is Int: " + (result is Int))
println("is Long: " + (result is Long))
println("is Float: " + (result is Float))
println("is Double: " + (result is Double))

A bit more casting safety:
infix fun Number.infixPlus(that: Number): Number {
return when {
this is Int && that is Int -> this + that
this is Double && that is Double -> this + that
this is Float && that is Float -> this + that
else -> throw Exception("Types mismatch")
}
}
In prev. example args:
val n1 = 1230000000000000000L
val n2 = 123
val result = n1 infixPlus n2
result: -1313144709
No exception and wrong result.

You have to find the correct type of the result:
val types = listOf("Double", "Float", "Long", "Integer", "Short", "Byte")
infix fun <T : Number> T.myPlus(that: T): T {
return when(types[min(types.indexOf(this.javaClass.simpleName), types.indexOf(that.javaClass.simpleName))]) {
types[0] -> (this.toDouble() + that.toDouble()) as T
types[1] -> (this.toFloat() + that.toFloat()) as T
types[2] -> (this.toLong() + that.toLong()) as T
types[3] -> (this.toInt() + that.toInt()) as T
types[4] -> (this.toShort() + that.toShort()) as T
types[5] -> (this.toByte() + that.toByte()) as T
else -> throw IllegalArgumentException()
}
}

Related

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

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())

Kotlin: Dynamically choose companion object function

My Enum class and companion object are as follows:
enum class Temperature(val names: List<String>) {
Celsius(listOf("degree Celsius", "degrees Celsius", "celsius", "dc", "c")),
Kelvin(listOf("Kelvin", "Kelvins", "k")),
Fahrenheit(listOf("degree Fahrenheit", "degrees Fahrenheit", "fahrenheit", "df", "f"));
companion object Conversion {
fun CelsiusToKelvin(c: Double) = c + 273.15
fun CelsiusToFahrenheit(c: Double) = (c * 9 / 5) + 32
fun FahrenheitToKelvin(f: Double) = (f + 459.67) * 5 / 9
fun FahrenheitToCelsius(f: Double) = (f - 32) * 5 / 9
fun KelvinToCelsius(K: Double) = K - 273.15
fun KelvinToFahrenheit(K: Double) = K * 9 / 5 - 459.67
}
}
I get input temperature in a scale which I need to convert to a different output scale. Is there a way to dynamically call the companion object functions based on the input and output scales?
For example:
var convert = "CelsiusToKelvin"
val value = 36.9
val myFunc = Temperature.getFunction(convert)
val myOutput = myFunc(value)
This should invoke the Temperature.CelsiusToKelvin function.
I know that I can check the input using if or when statements and manually invoke the function I want. But is it possible without doing this?
Edit 1:
I solved it using when by changing the function:
companion object Conversion {
fun convert(a:String,b:String,c:Double) = when {
a == "Celsius" && b == "Kelvin" -> c + 273.15
a == "Celsius" && b == "Fahrenheit" -> (c * 9 / 5) + 32
a == "Fahrenheit" && b == "Kelvin" -> (c + 459.67) * 5 / 9
a == "Fahrenheit" && b == "Celsius" -> (c - 32) * 5 / 9
a == "Kelvin" && b == "Celsius" -> c - 273.15
a == "Kelvin" && b == "Fahrenheit" -> c * 9 / 5 - 459.67
else -> 0.0
}
}
But I want to know if what I originally wanted to do was possible
I think a better approach, if you must use Strings, is to dynamically determine the constant, and have each constant provide the necessary conversion functions. For example:
// Note: Didn't include your "names" property
enum class Temperature {
Celsius {
override fun toKelvin(value: Double) = value + 273.15
override fun toFahrenheit(value: Double) = (value * 9.0 / 5.0) + 32.0
},
Kelvin {
override fun toCelsius(value: Double) = value - 273.15
override fun toFahrenheit(value: Double) = value * 9.0 / 5.0 - 459.67
},
Fahrenheit {
override fun toCelsius(value: Double) = (value - 32.0) * 5.0 / 9.0
override fun toKelvin(value: Double) = (value + 459.67) * 5.0 / 9.0
};
open fun toCelsius(value: Double) = value
open fun toKelvin(value: Double) = value
open fun toFahrenheit(value: Double) = value
fun convert(value: Double, target: Temperature) = when (target) {
Celsius -> toCelsius(value)
Kelvin -> toKelvin(value)
Fahrenheit -> toFahrenheit(value)
}
companion object {
fun convert(source: String, target: String, value: Double) =
valueOf(source).convert(value, valueOf(target))
}
}
The valueOf method, which is added implicitly by the compiler, will throw an IllegalArgumentException if the string does not match the name of an enum constant exactly. Your code has a similar requirement except you return 0 if there's no match. I personally prefer the exception.

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

Kotlin: Passing operator as a function parameter

I've the following function in Kotlin
fun evaluate(first:Int?, second:Int?) {
var result = 0
if (v.equals('*')) {
result = (first ?: 0) * (second ?: 0)
} else if (v.equals('+')) {
result = (first ?: 0) + (second ?: 0)
} else if (v.equals('-')) {
result = (first ?: 0) - (second ?: 0)
} else if (v.equals('/')) {
result = (first ?: 0) / (second ?: 0)
}
return result
}
I want to change it in a way so that I can pass as a third parameter needed operator and evalute the expression. Something like
fun evaluate(first:Int?, second:Int?, op: () -> Unit):Int {
return (first ?: 0).op(second ?: 0)
}
How can I pass the operator as a function in this case? I checked the same kind of a question, but it is not clear how you can do that with operator.
Writing a higher order function using a function type as a parameter allows using both built-in operators and lambda expressions for the operation, so this would look like:
fun evaluate(first: Int?, second: Int?, op: (Int, Int) -> Int): Int {
return op(first ?: 0, second ?: 0)
}
Which can be called with built-in operators such as:
val r1 = evaluate(value1, value2, Int::times)
val r2 = evaluate(value1, value2, Int::plus)
val r3 = evaluate(value1, value2, Int::minus)
val r4 = evaluate(value1, value2, Int::div)
And with custom functions:
val r5 = evaluate(value1, value2) { a, b -> (a * a) + b }
Now you can also assign the operators to variables, such as you v:
val v: (Int, Int)->Int = Int::times // typing needed on left to avoid ambiguous alternatives
// and then later...
val r6 = evaluate(value1, value2, v)
Note that a function written for signature Int.(Int)->Int can be passed into a parameter expecting (Int, Int)->Int because the receiver this will be passed in as the first parameter.
Change () -> Unit into Int.(Int) -> Int. Then all the other code should work as you've written it there.
On the calling side it this is the first int, and the first parameter is the second int: { other -> this * other }
you can try do that:
fun evaluate(first: Int?, second: Int? , v:String ): Int = v.op(first ?: 0, second ?: 0)
fun String.op(first:Int,second:Int):Int = when (this) {
"*" -> first * second
"+" -> first + second
//....
else -> throw Exception()
}
fun main(args: Array<String>) {
println(evaluate(2,3,"*"))
println(evaluate(2,3,"+"))
}

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)
}