Kotlin functions inside a const - kotlin

I am learning kotlin, and want to know how to add functions to a const,
here the JS example...
function suma (a, b){
return a + b
}
console.log("sua suma::", suma(2,3))
function multiplica (a, b){
return a * b
}
console.log("sua multiplik::", multiplica(2,3))
const operations = {
suma,
multiplica
}
console.log ("sum of first class::", operations.suma(2,3))
console.log ("mult of first class::", operations.multiplica(2,3))
so how do I achieve the same on Kotlin?
Here what I have tried:
fun suma(a: Int, b: Int): Int{
return a + b
}
fun multiplica (a: Int, b: Int): Int{
return a * b
}
const operations = {
suma(),
multiplica()
}
fun main() {
println("sua suma:: ${suma(2, 3)}")
println("sua multiplica:: ${multiplica(2, 3)}")
println("sua multiplica:: ${operations.multiplica(2,3)}")
}

It can be done using object keyword, like following:
fun suma(a: Int, b: Int): Int {
return a + b
}
fun multiplica(a: Int, b: Int): Int {
return a * b
}
fun main() {
val operations = object {
val _suma = ::suma
val _multiplica = ::multiplica
}
println("sua suma:: ${operations._suma(2, 3)}")
println("sua multiplica:: ${operations._multiplica(2, 3)}")
}
The only disadvantage is that you have to choose a name for operations.XXXXX that is different from the name of referenced function: note var _suma vs fun suma. Otherwise the compiler will consider it recursive problem

"Only Primitives and String are allowed" for const
The operator you're looking for is :: (Double colon)
An enum example of this is
enum class Operations(function: KFunction<Int>) {
Suma(function = ::suma),
Multiplica(function = ::multiplica)
}

The main issues here are that Kotlin is a statically typed language, and doesn't have the same idea of Objects that can contain arbitrary attributes, like Javascript does.
I'm kinda new to Kotlin, so there may be a better way to do this, but what I'd do is define a Map to do the same sort of thing:
fun suma(a: Int, b: Int): Int{
return a + b
}
fun multiplica (a: Int, b: Int): Int{
return a * b
}
val operations: Map<String, (a: Int, b:Int) -> Int> = hashMapOf(
"suma" to ::suma,
"multiplica" to ::multiplica)
fun main() {
println("sua suma:: " + operations.get("suma")?.invoke(2, 3))
println("sua multiplica:: " + operations.get("multiplica")?.invoke(2, 3))
}
Result:
sua suma:: 5
sua multiplica:: 6
Note that operations is an immutable Map ('const' kinda) in that its contents can't be changed once it's defined.
The access and having to use invoke seems kinda messy. This seems to be due to the fact that a Map can only contain nullable types. That's the main reason I think there's probably a better way to do this.

Related

Kotlin: How to define a variable whose type depends on the input?

I have a function in Kotlin which takes a particular string as input. Depending on the input, I want to create a variable of a specific type and do some computations on it.
For example,
fun compute(input: String): Any{
if(input=="2d"){
var point: Point2D;// Points2D - x: int, y: int
//initilize and do some computations
return point.findDistanceFromOrigin()
}else if(input=="2d-1"){
var point: Point2DWithP1AsOrigin;// Point2DWithP1AsOrigin - x: int, y: int
//initilize and do some computations
return point.findDistanceFromOrigin()
}else if(input=="2d-2"){
var point: Point2DWithP2AsOrigin;
//initilize and do some computations
return point.findDistanceFromOrigin()
}
.
.
.
}
You can see in the above example, I want to initilize the type of point depending on the input and do computation and return.
All the if-else conditions have the same code except for the definition of the variable. How can I put all this in a single block with something like this:
var point: if(input=="2d) Point2D::class else if(input=="2d-1") Point2DWithP1AsOrigin::class.....
How can I do that?
You could do something like this
fun compute(input: String): Any{
val point: MyPoint = when(input) {
"2d" -> Point2D()
"2d-1" -> Point2DWithP1AsOrigin()
"2d-2" -> Point2DWithP2AsOrigin()
else -> Point2D() //fallback is necessary
}
//initilize and do some computations
return point.findDistanceFromOrigin()
}
But then it's essential that all those classes share the same interface. Because they need to have the same methods in order to do the same operations on them.
For example like this:
class Point2D : MyPoint {
override fun findDistanceFromOrigin() = 5
}
class Point2DWithP1AsOrigin : MyPoint{
override fun findDistanceFromOrigin() = 6
}
class Point2DWithP2AsOrigin : MyPoint{
override fun findDistanceFromOrigin() = 7
}
interface MyPoint {
fun findDistanceFromOrigin() : Int
}
You can store constructor references and then invoke required one
fun main() {
val constructors = mapOf(
"2d" to ::Point2D,
"2d-1" to ::Point2DWithP1AsOrigin,
"2d-2" to ::Point2DWithP2AsOrigin,
)
val type = "2d-2"
val constructor = constructors[type] ?: throw IllegalArgumentException("$type not supported")
val point = constructor()
println(point::class)
}
Output
class Point2DWithP2AsOrigin

Operator overloading on += for set and get calls wrong setter

I have made an extension functions for BigIntegers, allowing me to add Ints to them.
operator fun BigInteger.plus(other: Int): BigInteger = this + other.toBigInteger()
// Allowing me to do
val c = myBigInt + 3
I have also made a Counter class, holding bigintegers for various keys, for easy counting. Since doing counter["1"] += myBigInt isn't allowed on standard maps (it's nullable), I have added a custom getter that returns a default value, making this possible.
class Counter<K>(val map: MutableMap<K, BigInteger>) : MutableMap<K, BigInteger> by map {
constructor() : this(mutableMapOf())
override operator fun get(key: K): BigInteger {
return map.getOrDefault(key, BigInteger.ZERO)
}
I can then use it like this
val counter = Counter<String>()
c["ones"] += 5.toBigInteger()
Problem is that I cannot use it like this:
c["ones"] += 5 // doesn't work, "Kotlin: No set method providing array access"
but this should be equivalent to this, which works, since it should use my extension operator on the bigint:
c["ones"] = c["ones"] + 5 // works
Why doesn't this work?
I've tried adding a set method for Ints, but then I see a very weird behavior. Kotlin will do the calculation correct, but then convert the BigInteger to an Int before passing it to my class! Example:
inline operator fun BigInteger.plus(other: Int): BigInteger {
val bigInteger = this + other.toBigInteger()
println("calculated bigint to $bigInteger")
return bigInteger
}
class Counter<K>(val map: MutableMap<K, BigInteger>) : MutableMap<K, BigInteger> by map {
constructor() : this(mutableMapOf())
override operator fun get(key: K): BigInteger {
return map.getOrDefault(key, BigInteger.ZERO)
}
operator fun set(key: K, value: Int) {
println("setting int $value")
map[key] = value.toBigInteger()
}
}
val c = Counter<String>()
c["1"] = "2192039569601".toBigInteger()
c["1"] += 5
println("result: ${c["1"]}")
c["1"] = "2192039569601".toBigInteger()
c["1"] = c["1"] + 5
println("result: ${c["1"]}")
Which prints
calculated bigint to 2192039569606
setting int 1606248646 <--- why does it call the int setter here?
result: 1606248646
calculated bigint to 2192039569606
result: 2192039569606
Why does Kotlin do the BigInt summation, but converts it back to an Int before sending to my setter?
Update
Since a comment suggest this is a compiler issue, any other ideas?
My ultimate goal here, was to have a counter of big integers, but to be able to easily add ints to it.
Adding this as a set function, makes it being called for both ints and bigints, so I can do the proper assignment myself. However, it will also then allow someone to add floats that will crash at runtime.
operator fun set(key: K, value: Number) {
map[key] = when (value) {
is BigInteger -> value
is Int -> value.toBigInteger()
else -> throw RuntimeException("only ints")
}
}
Any tips?
Notice that c["ones"] += 5 can be translated into calls in two ways:
c.set("ones", c.get("ones").plus(5))
c.get("ones").plusAssign(5)
The first way is what your code currently translates to, because you don't have a plusAssign operator defined. As I said in the comments, there is a bug in the compiler that prevents the operators from resolved correctly. When resolving c["ones"] += 5, It seems to be trying to find a set operator that takes an Int instead (possibly because 5 is an Int), which is unexpected. If you modify the code in the bug report a little, you can even make it throw an exception when executed!
class Foo {
operator fun get(i: Int) : A = A()
operator fun set(i: Int, a: A) {}
operator fun set(i: Int, a: Int) {}
}
class A {
operator fun plus(b: Int) = A()
}
class B
fun main(args: Array<String>) {
val foo = Foo()
foo[0] = foo[0] + 1
foo[0] += 1 // this compiles now, since there is a set(Int, Int) method
// but A can't be casted to Int, so ClassCastException!
}
It is rather coincidental (and lucky) in your case, that the compiler knows how to convert from BigInteger (or any other Number type actually) to Int, using Number#intValue. Otherwise the program would have crashed too.
A natural alternative way is to define the plusAssign operator, so that the assignment gets translated the second way. However, we can't do it on BigInteger, because plusAssign would need to mutate this, but BigInteger is immutable. This means that we need to create our own mutable wrapper. This does mean that you lose the nice immutability, but this is all I can think of.
fun main() {
val c = Counter<String>()
c.set("1", "2192039569601".toMutableBigInteger())
c.get("1").plusAssign(5)
println("result: ${c["1"]}")
}
data class MutableBigInteger(var bigInt: BigInteger) {
operator fun plusAssign(other: Int) {
bigInt += other.toBigInteger()
}
}
fun String.toMutableBigInteger() = MutableBigInteger(toBigInteger())
class Counter<K>(val map: MutableMap<K, MutableBigInteger>) : MutableMap<K, MutableBigInteger> by map{
constructor() : this(mutableMapOf())
override operator fun get(key: K): MutableBigInteger {
return map.getOrPut(key) { MutableBigInteger(BigInteger.ZERO) }
}
operator fun set(key: K, value: Int) {
println("setting int $value")
map[key] = MutableBigInteger(value.toBigInteger())
}
}
Notably, getOrDefault is changed to getOrPut - when a value is not found, we want to put the zero we return into the map, rather than just returning a zero that is not in the map. Our changes to that instance wouldn't be visible through the map otherwise.

Is it possible to write a "double" extension method?

In Kotlin, it is possible to write
class A {
fun B.foo()
}
and then e.g. write with (myA) { myB.foo() }.
Is it possible to write this as an extension method on A, instead? My use case is writing
with (java.math.RoundingMode.CEILING) { 1 / 2 }
which I would want to return 1, the point being that I want to add operator fun Int.div(Int) to RoundingMode.
No it's not possible. operator div is required to have Int as a receiver.
You can't add also RoundingMode as receiver, since there can only be single function receiver.
What you can do, though, is use Pair<RoundingMode, Int> as a receiver:
operator fun Pair<RoundingMode, Int>.div(i: Int): BigDecimal =
BigDecimal.valueOf(second.toLong()).divide(BigDecimal.valueOf(i.toLong()), first)
with(RoundingMode.CEILING) {
println((this to 1) / 2) // => 1
}
That's not possible, Int already has a div function, thus, if you decide to write an extension function div, you won't be able to apply it, because member functions win over extension functions.
You can write this though:
fun RoundingMode.div(x: Int, y: Int): Int {
return if (this == RoundingMode.CEILING) {
Math.ceil(x.toDouble() / y.toDouble()).toInt()
} else {
Math.floor(x.toDouble() / y.toDouble()).toInt()
}
}
fun main(args: Array<String>) {
with(java.math.RoundingMode.CEILING) {
println(div(1,2))
}
}
It's not possible for a couple of reasons:
There's no "double extension functions" concept in Kotlin
You can't override a method with extension functions, and operator div is already defined in Int
However you can workaround these issues with
A context class and an extension lambda (e.g. block: ContextClass.() -> Unit)
Infix functions (e.g. use 15 div 4 instead of 15 / 4)
See the example below:
class RoundingContext(private val roundingMode: RoundingMode) {
infix fun Int.div(b: Int): Int {
val x = this.toBigDecimal()
val y = b.toBigDecimal()
val res = x.divide(y, roundingMode)
return res.toInt()
}
}
fun <T> using(roundingMode: RoundingMode, block: RoundingContext.() -> T): T {
return with(RoundingContext(roundingMode)) {
block()
}
}
// Test
fun main(args: Array<String>) {
using(RoundingMode.FLOOR) {
println(5 div 2) // 2
}
val x = using(RoundingMode.CEILING) {
10 div 3
}
println(x) // 4
}
Hope it helps!

How to combine variable argument definitions and function with receiver in Kotlin

In Kotlin I am able to define a function that accepts a variable number of arguments (see: testVariableArguments below) and I can define a function with a specified receiver (see: testFunctionWithReceiver below). I am wondering if there is a way to combine both of these concepts?
fun main(args: Array<String>) {
testVariableArguments { a: Int -> println(a) }
testVariableArguments { a: Int, b: Int -> println("$a, $b") }
testVariableArguments { a: Int, b: Int, c: Int -> println("$a, $b, $c") }
testVariableArguments { a: Int, b: Int, c: Int, d: Int -> println("$a, $b, $c, $d") }
testFunctionWithReceiver {
doSomething()
doAnotherThing()
}
}
fun <R, T : Function<R>> testVariableArguments(function: T) {
val method = function::class
.java
.declaredMethods
// May need to do something else here to get the
// correct method in case the return type is
// expected to be Object, but for my case it
// would never be Object
.first { m -> m.name == "invoke" && m.returnType != Object::class.java }
val args = method
.parameterTypes
// Mapping to Int here for demonstration, in real
// situations would use the parameter types to
// create the correct value
.withIndex()
.map { i -> i.index }
// Not really needed, but would be if I were
// using multiple types and not just Int
.map { i -> i as Any }
.toTypedArray()
method.invoke(function, *args)
}
fun <R> testFunctionWithReceiver(function: MyInterface.() -> R) {
val myObject = object : MyInterface {
override fun doSomething() {
println("doing something")
}
override fun doAnotherThing() {
println("doing another thing")
}
}
function(myObject)
}
interface MyInterface {
fun doSomething()
fun doAnotherThing()
}
EDIT:
I have found a way to combine these two features, but it is a bit messy at the call site, so if there is a better approach I would be interested.
What I did was add the following operator function to MyInterface
operator fun <R, T : Function<R>> T.unaryPlus() {
testVariableArgumentDefinition(this)
}
Then when I call testFunctionWithReceiver I do the following:
testFunctionWithReceiver {
+{ a: Int, b: Int ->
println("$a, $b")
doSomething()
doAnotherThing()
}
}
You can add parameter requirements to the closure called with receiver by adding:
MyInterface.(P) -> R
Replacing your creation of test parameters with a fixed one, this is what it might look like:
fun <R, P> testVariableArgumentsWithReceiver(param: P, function: MyInterface.(P) -> R) {
function.invoke(myObject, param)
}
fun main(args: Array<String>) {
testVariableArgumentsWithReceiver(17) { a: Int ->
println("$a")
doSomething()
doAnotherThing()
}
}
Of course, you're not as flexible here as you need to pass a single value of type P (which could be an array). You can extend it to MyInterface.(P,Q) but not arbitrary signatures per se.
What you truly want is a signature like this:
fun <R, T: Function<R>> someName(function: MyInterface.T)
or
fun <R, T: FunctionWithReceiver<MyInterface, R>> someName(function: T)
To my knowledge, neither can currently be expressed:
Only function-type literals seem to be allowed as part of extension types; MyInterface.T is not valid code.
There doesn't seem to be a first-class type for functions with receiver; we can't declare FunctionWithReceiver.
This may be worthwhile to bring up on discuss.kotlinlang.org

What is the difference between these ways for defining functions?

I am from a background of Javascript trying to learn some Kotlin.
I know i can define my function by
fun add(a: Int , b: Int): Int{
return a+b
}
I am trying this
val add = {
a:Int,b:Int->
println("I am calculating the sale => no body you guy [$x+$y]");
//works
}
val add = { a:Int ,b : Int ->
//How do i return from this function
}
Also Is this a right way to define Kotlin functions? and Whats the difference with the first way ?
Also Is this a right way to define Kotlin functions? and Whats the difference with the first way ?
This is not even "a way to define Kotlin functions".
In JavaScript, all functions are reified: they are first-class values you can refer to from variables and pass around. Not so in Kotlin, just as in many other languages like Java, C++, Objective C and so on.
A function is just a declaration, you can call it but you can't otherwise directly refer to it. Separate language features allow you to create functional objects that delegate to these functions, and you can pass these objects around.
Therefore,
fun add(a: Int , b: Int): Int {
return a + b
}
is a function declaration and
val add = {a: Int, b: Int ->
a + b
}
is four things:
declaration of a variable add
declaration of an anonymous implementation of the functional type (Int, Int) -> Int
instantiation of this anonymous type, resulting in a functional object
assignment of the object to the variable add.
The object has a method invoke(a: Int, b: Int): Int whose implementation you have given in the block:
fun invoke(a: Int, b: Int): Int {
return a + b
}
You can call it explicitly:
val result = add.invoke(a, b)
and on top of that Kotlin defines syntax sugar that allows you to omit the explicit .invoke.
You don't need the explicit return there
val add = { a: Int, b: Int ->
a + b
}
add(2, 3) // => 5
Hopefully this will work.
val onChange = {
a:Int,b:Int->
println("I am calculating the sale => no body you guy [$x+$y]");
//works
}
val add = { a:Int ,b : Int ->
println("Sunm ${a+b}")
//How do i return from this function
}
Log.v("Response", add(4,3))
Output
V/Response: Sum 7
You can't return values in kotlin like this, it will give error of type mismatch as you havn't declared any return type :
fun add(a: Int , b: Int){
return a+b
} //wrong
we declare return type in kotlin as :
fun add(a: Int , b: Int) : Int{
return a+b
}
Secondly,
val add = { a:Int ,b : Int ->
}
this is not a function, its a declaration of value assignment
In kotlin we declare function by adding "fun" before your function name as
//you can add access modifiers(private,public,protected) if needed just before "fun"(by default its public)
fun add (){ //if it returns any value then add ": {datatype}" just right of "()"
//your code here
}
Hope it helped you :)