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