Johann Pardanaud
05/04/2023, 8:35 AMinterface MyInterface<T> {
val field1: Any
}
interface MyInterface<T: CharSequence>: MyInterface<Any> {
val field2: Any
}
Which could be used this way:
fun test(value1: MyInterface<Int>, value2: MyInterface<String>) {
value1.field1 // should work
value1.field2 // should NOT work, because it matches `MyInterface<T>`
value2.field1 // should work
value2.field2 // should work, because it matches `MyInterface<T: CharSequence>`
}
But I have two issues:
• MyInterface<T: CharSequence>
inheriting MyInterface<Any>
doesn’t seem to work due to a cyclic dependency
• value2: MyInterface<String>
doesn’t resolve to MyInterface<T: CharSequence>
, like I would have naively expected, but to MyInterface<T>
, which doesn’t allow to use field2
.
Is it possible or am I going down the wrong path here?ephemient
05/04/2023, 8:38 AMJoffrey
05/04/2023, 8:38 AMephemient
05/04/2023, 8:39 AMfun <T : CharSequence> MyInterface<T>.get2(): Any
but not something that requires a stateephemient
05/04/2023, 8:40 AMephemient
05/04/2023, 8:43 AMinterface MySubinterface<T : CharSequence> : MyInterface<T> {
val field2: Any
}
Johann Pardanaud
05/04/2023, 8:44 AMfun <T> wrapIt(): MyInterface<T>
Using generics I could avoid a switch in the function implementation to map a specific type to a specific interface/class to decorate it.Johann Pardanaud
05/04/2023, 8:45 AMJohann Pardanaud
05/04/2023, 8:45 AMJoffrey
05/04/2023, 8:54 AMfield2
. If you don't need anything special, e.g. if field2
can be computed from other state, then the extension approach suggested by @ephemient should do what you needJohann Pardanaud
05/04/2023, 9:46 AMMuhammad Utbah
05/04/2023, 11:11 AMMyInterface<Any>
, which is not type-safe. Instead, you can introduce another type parameter for the supertype of MyInterface<T>
, like this:
interface MyInterface<S, T> {
val field1: S
}
interface MyInterface<T: CharSequence>: MyInterface<Any, T> {
val field2: Any
}
Here, MyInterface<S, T>
has two type parameters, S
for the supertype of field1
and T
for the type parameter of the interface. MyInterface<T: CharSequence>
inherits from MyInterface<Any, T>
, which means that field1
has a supertype of Any
and field2
is added as a new property.
With this change, you can use the interfaces as you intended:
fun test(value1: MyInterface<Any, Int>, value2: MyInterface<Any, String>) {
value1.field1 // works
value1.field2 // does not compile, because it is not defined in MyInterface<Any, Int>
value2.field1 // works
value2.field2 // works, because it is defined in MyInterface<Any, String>
}
Note that you need to use MyInterface<Any, Int>
and MyInterface<Any, String>
as the types of the arguments to test
. This is because MyInterface<T: CharSequence>
only adds the field2
property, but field1
is still present and needs to be accessed through the supertype.Joffrey
05/04/2023, 11:25 AMMyInterface
twice