Unresolved reference Math in InteliJ IDEA Kotlin - kotlin

I have this code, it works, but compiler InteliJ IDEA doesn't see Math package and it's methods.
It defines Math like unresolved reference and propose to create class "Math". How to solve this problem?
import kotlin.math.*
fun main() {
println(five("rain"))
}
fun five(a: String) = a.substring(0, Math.min(5, a.length))

Just remove the Math. part. So like
fun five(a: String) = a.substring(0, min(5, a.length))
The import makes the min function available just like that. Don't need to write Math. in front of it

Related

Kotlin Polymorphism Confusion

I was following a tutorial for learning kotlin and ran into this example.
open class AquariumPlant(val color: String, private val size: Int)
class GreenLeafyPlant(size: Int) : AquariumPlant("green", size)
fun AquariumPlant.print() = println("AquariumPlant")
fun GreenLeafyPlant.print() = println("GreenLeafyPlant")
val plant = GreenLeafyPlant(size = 10)
plant.print()
println("\n")
val aquariumPlant: AquariumPlant = plant
aquariumPlant.print() // what will it print?
Well this apparently prints "Aquarium Plant" instead of "GreenLeafyPlant". I was a bit confused by this so I tested this out with this little snippet of code.
open class Aquarium {
open fun printSize() {
println("hello")
}
}
class TowerTank: Aquarium() {
override fun printSize() {
println("rawr")
}
}
fun main() {
towerTank = TowerTank()
(towerTank as Aquarium).printSize()
}
So this prints "rawr" and not "hello". My question is why doesn't it print "hello"? Aren't these two examples contradicting themselves? How does the function extensions create this difference in behaviour? Sorry if this may seem like a dumb question, I'm new to Kotlin as you can probably tell.
To understand this we need to understand how extensions work. Extensions don't magically add new members to existing classes. This is technically impossible both in Java and Kotlin. Instead, they work as good old static utility functions in Java. Accessing them as members is just a syntactic sugar.
First example is really similar to these functions:
fun print(plant: AquariumPlant) = println("AquariumPlant")
fun print(plant: GreenLeafyPlant) = println("GreenLeafyPlant")
To make it even more clear, we can rename these functions:
fun printAquariumPlant(plant: AquariumPlant) = println("AquariumPlant")
fun printGreenLeafyPlant(plant: GreenLeafyPlant) = println("GreenLeafyPlant")
Now, it is pretty clear that if we have object like this:
val aquariumPlant: AquariumPlant = GreenLeafyPlant(size = 10)
Then we can only invoke printAquariumPlant() function with it and it will print AquariumPlant, not GreenLeafyPlant. Despite the fact aquariumPlant is actually a GreenLeafyPlant object.
If we move one step back and rename them again to just print, nothing will really change. aquariumPlant variable is of type AquariumPlant (even if it contains GreenLeafyPlant object), so the compiler chooses print(AquariumPlant) function.
This is why we say extensions are resolved statically. Compiler decides which function to call at compile time. Virtual functions are resolved at runtime, taking into consideration the real type of the object.

Why cannot I create extension to BigDecimal in Kotlin?

I am trying to create an extension as a property and I experimented with an extension function as well, below an example for BigDecimal:
val BigDecimal.HUNDRED: BigDecimal
get() = TEN.multiply(TEN)
fun BigDecimal.HUNDRED_ONE(): BigDecimal {
return TEN.multiply(TEN)
}
It seems that Kotlin recognizes neither HUNDRED nor HUNDRED_ONE(). I am using Kotlin version 1.5.21.
Am I doing anything wrong on Kotlin version 1.5.21 that doesn't work correctly?
I have used this functionality before for lists. For instance:
fun <T> toList(list: List<T>?): List<T> {
return list ?: listOf()
}
I assume you wanted to use it like this:
val value = BigDecimal.HUNDRED
As far as I know, this is not possible in Kotlin right now. Extensions work on instances, so they're more like instance members, not static members. With your above code this will work: BigDecimal(0).HUNDRED.
I believe there is only one situation when it is possible to provide "static" extensions. If class has a companion (so it is Kotlin class) then we can add extensions to this companion. But this is not at all applicable to BigDecimal or any other Java class.

How to chain functions returning Validated, Option, Either? (Monad Transformer)

I have simple three functions returning arrow-kt data types
fun validate(input): Validated<Error, Input> = ...
fun fetch(input): Option<Error, InputEntity> = ...
fun performAction(inputEntity): Either<Error, Output> = ...
And want to chain something like this (can use any available function instead of map)
validate(input)
.map{fetch(it)}
.map{performAction(it)}
Only solution I could come up with is to replace Validated and Option with Either and chain using flatMap. Is there any better functional way to make it work without updating the existing functions?
👋 What #pablisco described is correct, but you can keep it simpler by using some syntax extensions we provide to convert from one type to the other. Note that both options are correct, but Monad Transformers can be a bit convoluted and too powerful, and they're also prone to get removed from Arrow soon, once we finally figure out our delimited continuations style completely. But that is out of scope here. Here is how you could solve it by using the extensions I mentioned:
import arrow.core.*
import arrow.core.extensions.fx
sealed class Error {
object Error1 : Error()
object Error2 : Error()
}
data class InputEntity(val input: String)
data class Output(val input: InputEntity)
fun validate(input: String): Validated<Error, InputEntity> = InputEntity(input).valid()
fun fetch(input: String): Option<InputEntity> = InputEntity(input).some()
fun performAction(inputModel: InputEntity): Either<Error, Output> = Output(inputModel).right()
fun main() {
val input = "Some input"
Either.fx<Error, Output> {
val validatedInput = !validate(input).toEither()
val fetched = !fetch(validatedInput.input).toEither { Error.Error1 /* map errors here */ }
!performAction(fetched)
}
}
Hope it was useful 👍
What you are looking for is called a Monad Transformer. In Arrow, you may have seen them already, they end with a T at the end. Like OptionT or EitherT.
There are some good examples here for EitherT:
https://arrow-kt.io/docs/0.10/arrow/mtl/eithert/
And here for OptionT:
https://arrow-kt.io/docs/0.10/arrow/mtl/optiont/
The idea would be that to choose what your final value is going to be (let's say Either) and using an FX block you can then use EitherT to convert the other types to an Either.

Import class and extension functions for the class simultaneously

When you are writing a class (here it will be a simple Integer class, so it will be easy to follow) and you are overloading operators, I already had a problem on how to overload the operator for a stranger class, which takes your object as a parameter. Look at this example:
package com.example
class Integer(var value: Int) {
operator fun plus(x: Integer) = Integer(value + x.value)
operator fun plus(x: Int) = Integer(value + x)
operator fun minus(x: Integer) = Integer(value - x.value)
operator fun minus(x: Int) = Integer(value - x)
override fun toString(): String {
return value.toString()
}
}
I simply overload simple operators so maybe another programmer can use these overloads to avoid creating functions on his own. Now I got following problem: When overloading operators for classes you don't own, you can create simple extension functions like this:
operator fun Int.plus(x: Integer) = Integer(x.value + this) // This is referencing to the actual `Int` object
operator fun Int.minus(x: Integer) = Integer(x.value - this)
...
but where do I got to place these extension functions to be imported automatically when the Integer class is being used?
// Main.kt
import com.example.Integer
fun main(args: Array<String>) {
val int1: Integer(2) + 3 // Compiles
val int2: 3 + Integer(2) // Doesn't compile unleast you add the extensions functions in `Integer` before the class declaration
// (between the package declaration and the class) and import them explicity
// like `import com.example.plus`
I could workaround this by import com.example.*, but then every single class in the package gets imported even if they remain unused. So how do I do this correctly?
Unless you want to place these extension functions into their own package and use a * import on that package, I don't see how you could make this any better. You just have to import the extension functions one by one, that's how the compiler knows where they come from. Otherwise you could have the same extension functions defined in multiple packages and files all over your project and there would be no way to choose between them.

Kotlin: Kotlin-script (.kts) cannot use regular code?

In my library's codebase, I have this package function: fun sayHello() = println("Hello there!")
The function is defined in the package org.jire.pomade
I would like to use this function in a .kts file like so: sayHello()
Unfortunately I can't seem to get code apart from Kotlin's own stdlib to work in Kotlin-script files.
The entirety of my script:
import org.jire.pomade.sayHello
sayHello()
The result of running the script:
pomade.kts:1:12: error: unresolved reference: jire
import org.jire.pomade.sayHello
^
pomade.kts:3:1: error: unresolved reference: sayHello
sayHello()
^
Anybody know why this is happening? Thanks.
This is a bug in the Kotlin plugin: https://youtrack.jetbrains.com/issue/KT-11618
I suggest to use holgerbrandl/kscript to manage dependencies of your script.
There is experimental support for maven imports in Kotlin scripts since 1.3.
Take a look at https://blog.jetbrains.com/kotlin/2018/09/kotlin-1-3-rc-is-here-migrate-your-coroutines/#scripting:
#file:Repository("https://jcenter.bintray.com")
#file:DependsOn("org.jetbrains.kotlinx:kotlinx-html-jvm:0.6.11")
import kotlinx.html.*
import kotlinx.html.stream.*
print(createHTML().html {
body {
h1 { +"Hello, World!" }
}
})
And here is the KEEP: https://github.com/Kotlin/KEEP/blob/master/proposals/scripting-support.md.
Alternative is using the Kotlin REPL instead.