The interaction between `reified` and interface me...
# language-evolution
c
The interaction between
reified
and interface methods is unfortunate. Let's say I have:
Copy code
interface Container<T> {
    fun <O> map(…): Container<O>
}
But, I want to know the type of the contents of the container (because of KotlinX.Serialization, because type parameters are erased).
Copy code
interface Container<T> {
    val type: KType
    fun <O> map(type: KType, …): Container<0>
}
That works, but specifying the
type
is not convenient, so I'd like to have a convenience overload:
Copy code
interface Container<T> {
    val type: KType
    fun <O> map(type: KType, …): Container<O>
    inline fun <reified O> map(…): Container<O> =
        map(typeOf<O>(), …)
}
but
inline
can't be used within interfaces, so
Copy code
interface Container<T> {
    val type: KType
    fun <O> map(type: KType, …): Container<O>
}

inline fun <T, reified O> Container<T>.map(…): Container<O> =
    map(typeOf<O>(), …)
This actually decreases developer experience quite a bit because IntelliJ will always auto-complete the inconvenient overload much higher than the convenient one. Also, I can't make the initial
.map
function
protected
, so I have to use opt-in annotations. But let's say that I have an implementation
Copy code
class Foo<T> {
    override fun <O> map(…): Foo<O>
}
Notice how it returns an instance of itself to users. Now that
.map
has become an extension function, it's not possible anymore to override it to change its output type. Also, it's not possible to have a
Container<Nothing>
anymore because
reified
forbids
Nothing
.
1
v
> That works, but specifying the
type
is not convenient You pass
KType
to get a serializer, right? Why not pass
KSerializer
instead of it, that would provide type safety.
c
Doesn't change the problem that you need
reified
extension functions, but yeah that would be possible. It's not my approach here because this API can be used with other serialization libraries than only KotlinX.Serialization, so I don't want to use
KSerializer
directly.
j
What about using
@PublishedApi
to make the less convenient one
internal
?
You could re-expose it as a separate extension method if you need to.
c
I don't think interface methods can be
internal
.
j
Curses
c
I would have loved making them
protected
, but yeah same.
w
One such example is actually kx serialization's
Json.encodeToString
and friends. For everyone new to the API, it requires a period of confusion before they realize they missed the import. I have never seen someone do it correctly on first try. (I consider these different from cases such as
CancellableContinuation.resume
, which is not about reified but is due to api evolution, not the inability to express it the right way from the first time).