How to call function from generic function without knowing the type? - kotlin

Is there a way to do the following?:
class Someotherthing
class SomeotherthingDTO
class Something
class SomethingDTO
fun convert(entity: Someotherthing): SomeotherthingDTO = SomeotherthingDTO()
fun convert(entity: Something): SomethingDTO = SomethingDTO()
fun <T, D> generic(entity: T): D {
// TODO: check here if there is convert() that accepts type T?! somehow? reflection? reification? or it will be possible only in the future by using typeclasses (KEEP-87)?
return convert(entity)
}
fun main() {
val x: SomethingDTO = convert(Something())
println(x.toString())
}
Currently, the result is: none of the following can be called with the arguments supplied...

You'll need multiple receviers for this to work (KEEP-87). With those you'll be able to "find" the receivers properly.
Until then what I usually do is to put Converters in a ConverterRegistry to do the conversion like this:
interface Converter<A, B> {
val fromClass: KClass<A>
val toClass: KClass<B>
fun convert(from: A): B
fun convertBack(from: B): A
}
interface ConverterRegistry {
fun <A, B> tryConvert(from: KClass<A>, to: KClass<B>): B?
}

Related

Map return type from input generic type in Kotlin

I have a function that returns IMyInterface
fun getValue(type: Types): IMyInterface? {}
But I have to always cast the return type in this way before I can use it:
getValue(Types.TypeInt)?.let { value ->
val usableVale = MyInterfaceAsInt.cast(value)
// more code...
}
MyInterfaceAsInt implements IMyInterface and I have no control over them.
The casting always depend of the input, so
Types.TypeInt -> MyInterfaceAsInt.cast(value)
Types.TypeLong -> MyInterfaceAsLong.cast(value)
...etc
Is there a way to define somthing like fun <T = Types> getValue(type: T) in a way that the return type can be inferred from type ?
I would like to do the casting inside getValue.
It looks like Types.TypesInt/Long/etc. are simply instances of the same type Types, not different types; and in fun <T> getValue(type: T), T has to be a type. So it doesn't seem to be possible.
But I would probably go the other way and define functions like
fun getValueAsInt(): MyInterfaceAsInt? = getValue(Types.TypeInt)?.let { MyInterfaceAsInt.cast(it) }
fun getValueAsLong(): MyInterfaceAsLong? = getValue(Types.TypeLong)?.let { MyInterfaceAsLong.cast(it) }
...
Another alternative which could be useful at least when the type can be inferred:
#Suppress("UNCHECKED_CAST")
inline fun <reified T : MyInterface> getValue(): T? = when(T::class) {
MyInterfaceAsInt::class -> getValue(Types.TypeInt)?.let { MyInterfaceAsInt.cast(it) }
MyInterfaceAsLong::class -> getValue(Types.TypeLong)?.let { MyInterfaceAsLong.cast(it) }
...
} as T

Kotlin generics with in produces Type mismatch when compiling

I´m working on a code with generics and when I use an in I got a TypeMismatch when compiling.
The code is the following:
open class A
class B:A()
data class DataContainer(val a:String,
val b:A)
interface Repo<T:A>{
fun setParam(param:T)
fun getParam():T
}
abstract class RepoImp<T:A>:Repo<T>{
private lateinit var parameter:T
override fun setParam(param: T) {
parameter = param
}
override fun getParam(): T {
return parameter
}
}
class BRepo:RepoImp<B>()
class Repo2(val repo: Repo<in A>){
fun process(b:DataContainer){
repo.setParam(b.b)
}
}
val repoB = BRepo()
val repo2 = Repo2(repoB)// Here I got: Type mismatch: inferred type is BRepo but Repo<in A> was expected
I also tried changing the attribute repo from Repo2 to Repo<*>
Since BRepo is a Repo<B>, it is not a Repo<in A>, (but it would satisfy Repo<out A>).
In other words, a Repo<in A> must be able to accept setParam(A()), but BRepo.setParam() can only accept a B or subclass of B.
Or to put it another way, BRepo is a Repo<B>, which is a tighter restriction on the type than Repo<A> when it comes to writing values (but looser restriction when reading values).
The reason class Repo2(val repo: Repo<*>) doesn't work is that Repo<*> is essentially a Repo<in Nothing/out A>. You can't call setParam() on a Repo<*> with any kind of object.
There's a design flaw in your code that you can't fix simply by changing Repo2's constructor signature. As it stands now, Repo2 needs to be able write A's to the object you pass to it, and a BRepo by definition does not support writing A's, only B's. You will need to make at least one of your class's definitions more flexible about types.
It might be easier to understand the covariance limitation with more common classes:
val stringList: MutableList<String> = ArrayList()
var anyList: MutableList<in Any> = ArrayList()
anyList.add(5) // ok
anyList = stringList // Compiler error.
// You wouldn't be able to call add(5) on an ArrayList<String>
Basically MutableList<String> is not a MutableList<in Any> the same way Repo<B> is not a Repo<in A>.
The Repo2 class expect to consume only type A, use Repo2<T : A>(val repo: Repo<in T>)
open class A
class B : A()
class C : A()
class D : A()
class BRepo : RepoImp<B>()
class CRepo : RepoImp<C>()
class DRepo : RepoImp<D>()
interface Repo<T : A> {
fun setParam(param: T)
fun getParam(): T
}
abstract class RepoImp<T : A> : Repo<T> {
private lateinit var parameter: T
override fun setParam(param: T) {
parameter = param
}
override fun getParam(): T {
return parameter
}
}
class Repo2<T : A>(val repo: Repo<in T>) {
fun process(b: DataContainer<T>) {
repo.setParam(b.b)
}
}
data class DataContainer<T : A>(
val a: String,
val b: T
)
fun main() {
val repoB = BRepo()
val repoC = CRepo()
val repoD = DRepo()
val repo2 = Repo2(repoB)
val repo3 = Repo2(repoC)
val repo4 = Repo2(repoD)
repo2.process(DataContainer("Process B type", B()))
repo3.process(DataContainer("Process C type", C()))
repo4.process(DataContainer("Process D type", D()))
println(repo2.repo.getParam())
println(repo3.repo.getParam())
println(repo4.repo.getParam())
}

How to flatMap vavr Either with left variance annotated

My code
open class Fail(override val message: String, override val cause: Throwable?) : RuntimeException(message, cause)
data class ValidationFail(override val message: String, override val cause: Throwable?) : Fail(message, cause)
more fails will be defined there in the future
i have 2 functions
fun fun1(): Either<out Fail, A>
fun fun2(a: A): Either<out Fail, B>
when i try to invoke them like this fun1().flatMap{fun2(it)}
i got
Type mismatch: inferred type is (A!) -> Either<out Fail, B> but ((A!) -> Nothing)! was expected. Projected type Either<out Fail, A> restricts use of public final fun <U : Any!> flatMap(p0: ((R!) -> Either<L!, out U!>!)!): Either<L!, U!>! defined in io.vavr.control.Either
Code from vavr Either:
default <U> Either<L, U> flatMap(Function<? super R, ? extends Either<L, ? extends U>> mapper) {
Objects.requireNonNull(mapper, "mapper is null");
if (isRight()) {
return (Either<L, U>) mapper.apply(get());
} else {
return (Either<L, U>) this;
}
}
I guess o have this error because there is L in flatMap definition not ? extends L
Any workaround for this ?
In your particular case, you can make it compile by removing out variance from fun1 and fun2 return type. You shouldn't use wildcard types as return types anyway.
But it won't help if you have fun1 and fun2 defined this way:
fun fun1(): Either<ConcreteFail1, A>
fun fun2(a: A): Either<ConcreteFail2, B>
Replacing L with ? extends L in flatMap signature will not help either because of ConcreteFail2 not being a subtype of ConcreteFail1. The problem is that Either is supposed to be covariant, but there is no such thing as declaration-site variance in Java. Although there is a workaround using Either#narrow method:
Either.narrow<Fail, A>(fun1()).flatMap { Either.narrow(fun2(it)) }
Of course, it looks odd and must be extracted to a separate extension function:
inline fun <L, R, R2> Either<out L, out R>.narrowedFlatMap(
crossinline mapper: (R) -> Either<out L, out R2>
): Either<L, R2> = narrow.flatMap { mapper(it).narrow }
Where narrow is:
val <L, R> Either<out L, out R>.narrow: Either<L, R> get() = Either.narrow(this)
I think Vavr doesn't provide its own narrowedFlatMap because this method requires using a wildcard receiver type, so it can't be a member method and must be a static one, which breaks all readability of operations pipelining:
narrowedFlatMap(narrowedFlatMap(narrowedFlatMap(fun1()) { fun2(it) }) { fun3(it) }) { fun4(it) }
But since we use Kotlin, we can pipeline static (extension) functions as well:
fun1().narrowedFlatMap { fun2(it) }.narrowedFlatMap { fun3(it) }.narrowedFlatMap { fun4(it) }

How to get rid of this boilerplate code in this sealed class hierarchy?

Suppose I've got a sealed class hierarchy like that:
sealed class A {
abstract val x: Int
abstract fun copyX(x1: Int): A
}
data class A1(override val x: Int, val s1: String) : A() {
override fun copyX(x1: Int): A {
return this.copy(x = x1)
}
}
data class A2(override val x: Int, val s2: String) : A() {
override fun copyX(x1: Int): A {
return this.copy(x = x1)
}
}
All the data classes have field x and should provide method copyX(x1: Int) to copy all the fields but x and override x with x1. For instance,
fun foo(a: A): A { a.copyX(100) }
The definitions above probably work but the repeating copyX across all the data classes seem very clumsy. How would you suggest get rid of this repeated copyX ?
First, you can implement copyX as an extension (or even A's member) so as to concentrate the code in one place and avoid at least duplicating the copyX function in the sealed class subtypes:
sealed class A {
abstract val x: Int
}
fun A.copyX(x1: Int): A = when (this) {
is A1 -> copy(x = x1)
is A2 -> copy(x = x1)
}
data class A1(override val x: Int, val s1: String) : A()
data class A2(override val x: Int, val s2: String) : A()
If you have a lot of sealed subtypes and all of them are data classes or have a copy function, you could also copy them generically with reflection. For that, you would need to get the primaryConstructor or the function named copy from the KClass, then fill the arguments for the call, finding the x parameter by name and putting the x1 value for it, and putting the values obtained from component1(), component2() etc. calls or leaving the default values for the other parameters. It would look like this:
fun A.copyX(x1: Int): A {
val copyFunction = this::class.memberFunctions.single { it.name == "copy" }
val args = mapOf(
copyFunction.instanceParameter!! to this,
copyFunction.parameters.single { it.name == "x" } to x1
)
return copyFunction.callBy(args) as A
}
This works because callBy allows omitting the optional arguments.
Note that it requires a dependency on kotlin-reflect and works only with Kotlin/JVM. Also, reflection has some performance overhead, so it's not suitable for performance-critical code. You could optimize this by using the Java reflection (this::class.java, getMethod(...)) instead (which would be more verbose) and caching the reflection entities.

Why Kotlin can not override List<*> operator method?

Here is my function:
operator infix fun List<Teacher>.get(int: Int): Teacher {
var t = Teacher()
t.name = "asd"
return t ;
}
and my usage:
b[0].teachers[1].name
tip: b is an object that has List< Teacher > property
and the errorEmpty list doesn't contain element at index 1.
why this override operator function doesn't work?
In Kotlin, you cannot shadow a member function with an extension. A member always wins in the call resolution. So, you basically cannot call an extension with a signature same to that of a member function, that is present in the type that was declared or inferred for the expression.
class C {
fun foo() { println("member") }
}
fun C.foo() { println("extension") }
C().foo() // prints "member"
In your case, the member function is abstract operator fun get(index: Int): E defined in kotlin.collections.List.
See the language reference: Extensions are resolved statically
As voddan mentions in the comment, you can't overshadow a method with an extension. However, there is a way to get around this with some polymorphism. I don't think I would recommend doing this in your case, but I guess it shows off a cool Kotlin feature.
If b[0] returns an object of type B, you could do this in that class:
data class B(private val _teachers: List<Teacher> = emptyList()) {
private class Teachers(private val list: List<Teacher>) : List<Teacher> by list {
override operator fun get(int: Int): Teacher {
var t = Teacher()
t.name = "asd"
return t ;
}
}
val teachers: List<Teacher> = Teachers(_teachers)
}
fun main(args: Array<String>) {
println(B().teachers[0].name) // Prints "asd"
}
When I override the get-function it will affect everyone that uses the B class, not just where you would import the extension-function.
Note that I am delegating all other method-calls on the Teachers-class through to the underlying list.