Multiple types in Generic Extensions


#1

Currently i’m writing extensions function to LocalDate, LocalDateTime and couple of own types and It would be extremely useful to be able to define couple types in when clause if all of them expose required methods even if they don’t implement shared interface. This is bigger problem for 3rd party types for which I cannot add common interface. Currently I need to define multiple methods (one for each type)

fun <T : LocalTime> T.isBetweenStartInclusive(start: T, end: T): Boolean
{
    return !this.isBefore(start) && this.isBefore(end)
}

or

fun <T> T.isBetweenStartInclusive(start: T, end: T): Boolean
        where T : LocalTime {
    return !this.isBefore(start) && this.isBefore(end)
}

it would be extremly helpfull if I could write just

fun <T : LocalTime, LocalDateTime > T.isBetweenStartInclusive(start: T, end: T): Boolean
{
    return !this.isBefore(start) && this.isBefore(end)
}

or

fun <T> T.isBetweenStartInclusive(start: T, end: T): Boolean
        where T : LocalTime, LocalDateTime  {
    return !this.isBefore(start) && this.isBefore(end)
}

Where clause could even work as when statement containing multiple version of function implementation depending on type, although I think at that point you should probably keep code as separate functions to follow single responsibility principle.


#2

I fully see where you are coming from. There are sort of three ways of providing this capability ():

  • Duck-typing: within the code body at every call site check the actual type and invoke the “correct” method – this is needed on any platform (not only JVM) except javascript as it uses duck typing itself (but you may slow down the jitted code)
  • Indirection type: Create a wrapper interface/abstract sealed class that has implementations for all types (forwarding) and have the specific implementations invoke a generic one with the wrapped value. This could be generated in cases, but is sufficiently surprising to leave it to developers
  • Templates: Instead of having one compiled function, generate multiple implementations that differ on the type (C++ like). The JVM doesn’t have any special support for it although invokedynamic might be able to be abused for it (to generate the code at runtime). To ask templates from Kotlin is a very big ask, and it suffers from all kinds of problems including the problem of allowing templates for types that are not known (possibly written afterwards) to the template writer. Implementing templates on the JVM this is a major interop headache once you don’t want to require enumerated parameter types. I’m not clear on the details, but from what I understand compiler plugins are intended to allow some of this to happen, we’re not there yet though.

#3

Structural typing or type classes are considered for a future version of Kotlin. Meta programming is another planned feature, but I think structural typing would be the best fit for the problem.

See Future of Kotlin - How agile can language development be? by Andrey Breslav.


#4

Thanks for your responses. It’s good to hear that such feature is planned. Just for completeness I see one more way to provide this capability:

  • use this syntax as syntactic sugar, and at compile time generate functions for all enumerated in clause types. This would help with code maintenance (less code duplication) and also ships all runtime problems because it would just ignore other types.