Generic constraints

Up to now, we could have substituted the generic parameter with any type. Sometimes, you may want to restrict the generic types and this can be done with generic constraints. Constraints are specified in angle brackets, with a colon, and the type that is the limit after the generic parameter. Here’s how you can limit the generic type to the Number type:

interface Countable<T: Number> 
{
fun count(): T
}

This is known as the upper bound constraint, and the compiler will allow you to substitute the generic type with the Number type and all of its subtypes. Since the Int type is a subtype of the Number type, the compiler allows this:

class IntCountable: Countable<Int> 
{
override fun count(): Int
{
return 0
}
}

But, the string type is not a subtype of Number, so the next example will not compile:

//compiler error
class StringCountable: Countable<String> {
override fun count(): String {
return ""
}
}

Constraints can also be declared with the where keyword after the class or function declaration. The Countable interface could have also been declared like this:

interface Countable2<T> where T: Number {
fun count(): T
}

You can also have multiple constraints on a single generic parameter. When more than one constraint is specified, they have to use the where keyword. You use a comma to separate all the constraints. This interface puts a constraint on a Number type and Comparable interface:

interface Countable3<T> where T: Number, T: Comparable<T> {
fun count(): T
}

Constraints also work on generic functions; the syntax is the same as for declaring them on types.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.223.123