Upper bound is used with generic types. It provides the upper bound for generic type.
For example,
trait Person:
val name: String
case class Student(name: String, grade: Char) extends Person
def printOnConsole[T <: Person](obj: T): Unit =
val name = obj.name
println(s"Hello $name")
printOnConsole(Student("A", 'A'))
So, printOnConsole
can only take type T
which is a subtype of Person
. Doing printOnConsole(A("A"))
will give compilation error.