Mikhail Buzuverov
05/10/2021, 3:36 PMabstract class MockedMethod<in I, out O> {
abstract fun execute(arg: I): O
abstract fun combine(method: MockedMethod<I, O>): MockedMethod<I, O>
}
But I get error for combine argument:
Type parameter I is declared as 'in' but occurs in 'out' position in type MockedMethod<I, O>
Type parameter O is declared as 'out' but occurs in 'in' position in type MockedMethod<I, O>
I don't understand why there is error. What is wrong?Mikhail Buzuverov
05/10/2021, 3:42 PMclass A
class A1: A()
class B
class B1: B()
val method1 = MockedMethod<A1, B>()
val method2 = MockedMethod<A, B1>()
val combined: MockedMethod<A1, B> = method1.combine(method2) //correct, isn;t it? Because we can cast A1 to A and B1 to B
kevinherron
05/10/2021, 4:12 PMI
and O
are both used in both in and out positions (accepted by combine
and returned by combine
)Roukanken
05/10/2021, 4:12 PMRoukanken
05/10/2021, 4:13 PMabstract class MockedMethod<in I, out O> {
abstract fun execute(arg: I): O
abstract fun combine(method: MockedMethod<I, Any>): MockedMethod<Any, Any>
}
this, and various variants to it, throw tooRoukanken
05/10/2021, 4:13 PMandries.fc
05/10/2021, 5:28 PMabstract class MockedMethod<in T, out R> {
abstract fun execute(arg: T): R
abstract fun combine(mockedMethod: MockedMethod<Any, Any>): MockedMethod<T, R>
}
May be a bit tricky to handle the call the combine as you have no type safety any more.andries.fc
05/10/2021, 5:37 PMabstract class MockedMethod<in T, out R> {
abstract fun execute(arg: T): R
}
fun <T,R> MockedMethod<T,R>.combine(m: MockedMethod<T,R>): MockedMethod<T, R> {
return object : MockedMethod<T,R>() {
override fun execute(arg: T): R {
TODO("Implement combine")
}
}
}
Mikhail Buzuverov
05/11/2021, 1:20 AMabstract class MockedMethod<I, O> {
abstract fun execute(arg: I): O
abstract fun combine(method: MockedMethod<in I, out O>): MockedMethod<I, O>
}
But it looks weird. Why is there error when in
and out
in class definition, but no error when they are in method definition?
Looks like compiler bug.Mikhail Buzuverov
05/11/2021, 2:14 AMMikhail Buzuverov
05/11/2021, 2:14 AMMikhail Buzuverov
05/11/2021, 2:17 AMMikhail Buzuverov
05/11/2021, 5:52 AMI
is allowed:
interface Processor<in I, out O> {
fun setArg(arg: I)
fun process(fn: (I) -> O): O
}
interface A {
val a: Int
}
interface B: A {
val b: Int
}
class ProcessorImpl: Processor<A, Int> {
lateinit var value: A
override fun setArg(a: A) { value = a }
override fun process(fn: (A) -> Int): Int = fn(value)
}
fun main() {
val p1: Processor<A, Int> = ProcessorImpl()
p1.setArg(object: A { override val a = 10 }) //OK: type argument is compartible
val p2: Processor<B, Int> = p1 //OK: B can be casted to A and A is contravariant
p2.process { it: B -> it.b } //Ohhhh... Function expects B, but there is A as argument
}
So, Kotlin (and Scala) rejects this case absolutely correctly.