I wanted to get some clarity around how typealiases work with generic boundaries.
data class Entity<I : Any, T : Any>(
val id: I,
val type: T
)
typealias RetrieveEntity<I, T> = (I) -> Entity<I, T>
fun interface EntityRepository<I, T> : RetrieveEntity<I, T>
I have an Entity class made of two parameters, neither can be null. I’ve defined a RetrieveEntity alias as a function that takes in an id, and returns an Entity with that id. I’ve also defined an EntityRepository functional interface that uses the RetrieveEntity alias.
I know that I can’t specify any type boundaries on the typealias. This lead me to believe that the type boundaries would be inferred/implied based on the aliased type, in this case Entity.
It turns out though, that I can define an EntityRepository alias with nullable types.
typealias StringIntRepository = EntityRepository<String, Int>
typealias NullableStringIntRepository = EntityRepository<String?, Int?>
This doesn’t cause any compilation issues, until I try to make an implementation of the EntityRepository.
class StringIntRepositoryImpl : StringIntRepository {
override fun invoke(p1: String): Entity<String, Int> {
TODO("compiles fine")
}
}
class NullableStringIntRepositoryImpl : NullableStringIntRepository {
override fun invoke(p1: String?): Entity<String?, Int?> {
TODO("does not compile: Type argument is not within its bounds")
}
}
val y = EntityRepository<String?, Int?> {
TODO("compiles fine")
}
It seems the issue gets pushed down to the lowest possible point before a compilation error occurs. No compilation error happens until we try to reference an Entity with nullable boundaries; preventing construction, or preventing explicitly mentioning the return type. We can define type aliases that can’t effectively use, due to the boundaries on the aliased type.
But, even though I can define an EntityRepository this way, I can’t actually define an alias for the RetrieveEntity this way.
typealias NullableStringIntRetrieveEntity = RetrieveEntity<String?, Int?>
// Type argument resulting from type alias expansion is not within required bounds for 'I': should be subtype of 'Any', substituted type is 'String?'
It seems like this error should also occur on the interface definition, but it doesn’t.
Is this the expected behavior?