Extension functions for general classes in Kotlin

What is wrong with my extension function below

class Foo<T> { fun <T> Foo<T>.plus(that: Foo<T>): Foo<T> = throw Exception() init { Foo<Int>() + Foo<String>() // A receiver of type Foo<T> is required } } 

Update

I wonder why this differs from regular extension functions, where T is successfully defined as Any and wants to achieve the same behavior, e. Mr. T to get the output as Foo <Any>

 class Foo { fun <T> T.foo(that: T): T = throw Exception() init { "str" foo 42 } } 
+5
source share
2 answers

The problem is how generics work.

 class Foo { fun <T> T.foo(that: T): T = throw Exception() init { "str" foo 42 } } 

This works because the compiler can find a T that matches both the signature of the function and the arguments: it is Any , and the function turns into this:

 fun Any.foo(that: Any): Any = ... 

String is now a subtype of Any , Int is a subtype of Any , so this function applies to arguments.

But in the first example:

 class Foo<T> { fun <T> Foo<T>.plus(that: Foo<T>): Foo<T> = throw Exception() init { Foo<Int>() + Foo<String>() // A receiver of type Foo<T> is required } } 

Everything is different. There is no such T Let naive and try Any :

 fun Foo<Any>.plus(that: Foo<Any>): Foo<Any> = ... 

Now Foo is invariant in T , so Foo<Int> is not a subtype of Foo<Any> , and in fact there is no type T except Int , which will make Foo<T> supertype of Foo<Int> . So T must be exactly Int , but it must also be exactly String by the same logic (due to the second argument), so there is no solution, and the function is not applicable.

You can make it work by making a co-variant of Foo in T :

 class Foo<out T> { fun <T> Foo<T>.plus(that: Foo<T>): Foo<T> = throw Exception() init { Foo<Int>() + Foo<String>() // A receiver of type Foo<T> is required } } 

This imposes some restrictions on the possible signatures of Foo members, but if you are okay with them, this fixes your problem.

Take a look at this link for more details: http://kotlinlang.org/docs/reference/generics.html

+11
source

Your plus method expects the parameter to have the same type T parameter as the receiver. Therefore, you cannot add Foo<String> to Foo<Int> .

If you want to add all types of Foo , you need to declare your extension function as follows:

 operator fun <T,R> Foo<T>.plus(that: Foo<R>): Foo<T> = throw Exception() 
0
source

Source: https://habr.com/ru/post/1232691/


All Articles