What if your functions could automatically know which types they can work with, without you writing extra checks?
Why Type constraints with upper bounds in Kotlin? - Purpose & Use Cases
Imagine you want to write a function that works only with certain types, like numbers or shapes, but you have to check each type manually every time you use it.
This manual checking makes your code long, confusing, and easy to break. You might forget a type or write repeated code for each case, which wastes time and causes bugs.
Type constraints with upper bounds let you tell the computer exactly which types are allowed, so your function automatically works only with those types. This keeps your code clean, safe, and easy to reuse.
fun printArea(shape: Any) {
if (shape is Circle) println(shape.radius * shape.radius * 3.14)
else if (shape is Square) println(shape.side * shape.side)
}fun <T : Shape> printArea(shape: T) {
println(shape.area())
}You can write flexible, reusable functions that work safely with a group of related types without extra checks.
Suppose you build a drawing app that handles different shapes. Using type constraints, you can create one function to calculate areas for all shapes that share a common interface.
Manual type checks make code long and error-prone.
Upper bounds let you restrict types clearly and safely.
This leads to cleaner, reusable, and safer code.
Practice
<T : Number> mean in Kotlin generics?Solution
Step 1: Understand the upper bound syntax
The syntax<T : Number>means T is limited to types that inherit from Number.Step 2: Interpret subtype relationship
This means T can be Number or any subclass like Int or Double, but not unrelated types.Final Answer:
T must be a subtype of the Number class -> Option AQuick Check:
Upper bound <T : Number> = subtype limit [OK]
- Thinking T can be any type
- Confusing subtype with supertype
- Assuming exact type match only
Solution
Step 1: Recall Kotlin's upper bound syntax
Kotlin uses<T : Interface>to specify T must implement that interface.Step 2: Identify correct syntax for Comparable
The correct syntax isfun <T : Comparable<T>> .... Options B and D use Java syntax, and A uses a where clause but with incorrect syntax.Final Answer:
fun <T : Comparable<T>> max(a: T, b: T): T { ... } -> Option BQuick Check:
Kotlin upper bound uses ':' not 'implements' or 'extends' [OK]
- Using Java syntax keywords like 'implements' or 'extends'
- Confusing where clause syntax
- Missing generic type parameter declaration
fun <T : Number> printDouble(value: T) {
println(value.toDouble() * 2)
}
fun main() {
printDouble(5)
printDouble(3.5)
}Solution
Step 1: Understand the generic constraint
The function requires T to be a subtype of Number, so Int and Double are valid.Step 2: Calculate the output
For 5 (Int), toDouble() is 5.0, multiplied by 2 is 10.0.
For 3.5 (Double), toDouble() is 3.5, multiplied by 2 is 7.0.Final Answer:
10.0 and 7.0 -> Option DQuick Check:
Number constraint allows toDouble(), output matches calculations [OK]
- Expecting compilation error for Int argument
- Confusing printed values with input values
- Thinking toDouble() causes runtime error
fun <T : Comparable> compareValues(a: T, b: T): T {
return if (a > b) a else b
}Solution
Step 1: Check Comparable usage
Comparable is a generic interface and requires a type parameter, so it should be Comparable<T>.Step 2: Understand operator usage
The '>' operator is not directly supported for Comparable, but Kotlin allows it if Comparable<T> is specified and operator overloading is present.Final Answer:
Missing generic type parameter in Comparable -> Option CQuick Check:
Comparable must be parameterized as Comparable<T> [OK]
- Omitting generic parameter in Comparable
- Assuming '>' works without Comparable<T>
- Confusing return type requirements
fun <T : Number> sumList(numbers: List<T>): Double {
return numbers.sumOf { it.toDouble() }
}Which of these calls will cause a compilation error?
Solution
Step 1: Analyze the function's type constraint
The function requires a List of elements where each element is a subtype of Number.Step 2: Check each call's argument type
Options B, C, and D pass lists of Double, Int, and Long respectively.
sumList(listOf("1", "2", "3")) passes a list of Strings, which are not subtypes of Number, causing a compilation error.Final Answer:
sumList(listOf("1", "2", "3")) -> Option AQuick Check:
Only Number subtypes allowed, String list fails [OK]
- Passing String list instead of Number list
- Assuming any list works
- Ignoring generic type constraints
Ready to prove it?
Pass the test and this pattern moves unknown
