Generics Functions in Kotlin

Using functions with Generics in Kotlin.

fun main() {

    val ints = listOf(1, 2, 3, 4, 5)
    val shorts: List<Short> = listOf(10, 20, 30, 40, 50)
    val floats: List<Float> = listOf(100.3f, -458.43f)
    val strings = listOf("1", "2", "3")

    val nullableShorts: List<Short?> = listOf(10, 20, 30, 40, 50)

    convertToInt2(ints)
    println("======")
    convertToInt2(shorts)
    println("======")
    convertToInt2(floats)
    println("======")
//    convertToInt2(strings) // Nope

    append(StringBuilder("String 1"), StringBuilder("String 2")) // StringBuilder conforms to both CharSequence and Appendable
    println("======")

    convertToInt(nullableShorts) // Will accept because the Generic T has no bounds and is therefore nullable
    println("======")
    convertToInt3(nullableShorts) // Works as convertToInt3() accepts nullable Numbers

}

fun <T> convertToInt(collection: Collection<T>) {
     for (num in collection) {
//         println("${num.toInt()}") // Will not accept this as there is no guarantee that what is being passed in is a Number
     }
}

// So we restrict the Generic type to a Number class to limit type options:
fun <T: Number> convertToInt2(collection: Collection<T>) {
    for (num in collection) {
         println("${num.toInt()}") // Works as the compiler knows it is getting a Number
    }
}

fun <T> append(item1: T, item2: T)
where T: CharSequence, T: Appendable { // Restricts to both CharSequence and Appendable. Can have multiple interfaces but only one class as an object cannot be e.g. an Int and Short at the same time
    println("Append result is ${item1.append(item2)}")
}

// What about nullability? Generic defaults to Any? type so is nullable. But if we specify a bound we need to state nullable if necessary

// So we restrict the Generic type to a Number class to limit type options:
fun <T: Number?> convertToInt3(collection: Collection<T>) { // Use ? to allow null
    for (num in collection) {
        println("${num?.toInt()}") // Remember to add nullable here too
    }
}

// If you want to limit the Collection to only non-nullable types:
fun <T: Any> convertToInt4(collection: Collection<T>) { // Use Any without the ? to specify a non-nullable of any type
    for (num in collection) {
        println(num)
    }
}