🎓 A1Learner
🔍
0 of 48 lessons completed

Scala Lower Bounds

A lower bound is a limit on a type parameter that says how low a type may go. It requires every type used to be that type or a type above it.

Adding a dog keeps a dog kennel

The kennel starts with one dog. Adding a second dog keeps the kennel a kennel of dogs.

class Animal(val name: String)
class Dog(name: String) extends Animal(name)
class Cat(name: String) extends Animal(name)
class Kennel[A](val members: List[A]):
  def add[B >: A](newcomer: B): Kennel[B] = Kennel(newcomer :: members)
@main def main(): Unit =
  val dogs = Kennel(List(Dog("Rex")))
  val more = dogs.add(Dog("Max"))
  println(more.members.map(_.name))

Adding an animal widens the kennel

The kennel starts with one dog. Adding an animal widens it to a kennel of animals.

class Animal(val name: String)
class Dog(name: String) extends Animal(name)
class Cat(name: String) extends Animal(name)
class Kennel[A](val members: List[A]):
  def add[B >: A](newcomer: B): Kennel[B] = Kennel(newcomer :: members)
@main def main(): Unit =
  val dogs = Kennel(List(Dog("Rex")))
  val mixed = dogs.add(Animal("Sam"))
  println(mixed.members.map(_.name))
  println(mixed.members.length)

A lower bound accepts both a dog and an animal

withRex takes a value of Dog or above. It builds a list of two in both calls.

class Animal(val name: String)
class Dog(name: String) extends Animal(name)
class Cat(name: String) extends Animal(name)
def withRex[T >: Dog](other: T): List[T] = List(Dog("Rex"), other)
@main def main(): Unit =
  println(withRex(Dog("Max")).length)
  println(withRex(Animal("Sam")).length)

Example

class Animal(val name: String)
class Dog(name: String) extends Animal(name)
class Cat(name: String) extends Animal(name)
class Kennel[A](val members: List[A]):
  def add[B >: A](newcomer: B): Kennel[B] = Kennel(newcomer :: members)
@main def main(): Unit =
  val dogs = Kennel(List(Dog("Rex")))
  val withDog = dogs.add(Dog("Max"))
  val mixed = withDog.add(Animal("Sam"))
  println(withDog.members.map(_.name))
  println(mixed.members.map(_.name))
  println(mixed.members.length)

Key points

  • Bound syntax: T >: Dog means T is Dog or a type above Dog, such as Animal.
  • Accepting supertypes: a method with this bound can accept an Animal value as well as a Dog value.
  • Widening containers: adding an Animal to a kennel of dogs widens the kennel to a kennel of animals.
  • Method arguments: a lower bound is often used when a method takes in a value.

In this example, the kennel starts with one dog, adding a dog keeps two dogs in order with the newest first, and adding an animal widens the kennel to three animals.

Note

a lower bound is a floor, so Cat does not satisfy T >: Dog because Cat is not Dog and not above Dog.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Scastie

Exercise

What does T >: Dog allow?