https://kotlinlang.org logo
#language-evolution
Title
# language-evolution
o

Oliver.O

08/18/2021, 9:07 PM
I have a use-case where I'd like to invoke a generic method from a generic class with and without a type like this: •
get()
get<DateModel>()
Currently, it requires two function definitions to achieve the goal, which might be resolved by introducing a default type for a type parameter as shown in the following example:
Copy code
package genericMethodDefaultType

open class Model

open class AttributeModel : Model()

data class DateModel(var value: String) : AttributeModel()

val modelCache = mutableMapOf<Int, Model>()

@Suppress("UNCHECKED_CAST")
class ModelReference<SpecificModel : Model>(private val modelId: Int) {
    // Variant (1) returning the default type.
    fun get() = modelCache[modelId]!! as SpecificModel

    // Variant (2) returning a derivative.
    @JvmName("getSpecific")  // required to disambiguate JVM signatures
    fun <MoreSpecificModel : SpecificModel> get() = modelCache[modelId]!! as MoreSpecificModel

    // Variant (3) replacing (1) and (2) – currently not valid Kotlin:
    //     fun <MoreSpecificModel = SpecificModel : SpecificModel> get() = modelCache[modelId]!! as MoreSpecificModel
    //
    //     Note the specification of a default type ` = SpecificModel` which shall be used if type inference cannot
    //     determine a result.
}

@Suppress("UNUSED_VARIABLE")
fun main() {
    val modelId = 42

    modelCache[modelId] = DateModel("2021-08-18")

    val attributeModelReference = ModelReference<AttributeModel>(modelId)

    // Some code would access attribute models like this:
    val attributeModel1 = attributeModelReference.get()
    // Does not compile if `get()` variant (1) is not defined: Not enough information to infer type variable MoreSpecificModel

    // If `get()` variant (1) is not defined, we would have to specify the type redundantly like this:
    val attributeModel2 = attributeModelReference.get<AttributeModel>()

    // A date view might want to access its model like this:
    val dateModel = attributeModelReference.get<DateModel>()

    println(attributeModel1)
    println(attributeModel2)
    println(dateModel)
}
Is this too exotic or do there exist better solutions for the above case?
e

elizarov

08/19/2021, 10:42 AM
o

Oliver.O

08/19/2021, 10:46 AM
Thanks for the reference, I'll add my use case there. Comments still welcome here! 🙂
e

elizarov

08/19/2021, 10:48 AM
A typical work-around now is to have two different names for those functions. It does not happen that much often in practice, so I cannot say there’s any kind of established convention for it now.
o

Oliver.O

08/19/2021, 10:51 AM
Yes that's also possible. I have used a
generic
prefix for the function returning the more generic type. I still prefer the above variants (1) plus (2) as these allow invocations via the same name as if type inference was working as usual.
3 Views