scala/basic

F-Bound

wefree 2022. 11. 12. 20:54

아래 코드를 생각해 보자

trait Animal {
  def breed: List[Animal]
}

class Dog extends Animal {
  override def breed: List[Animal] = ???
}

 

Dog class 의 breed 의 리턴 타입을 List[Animal] 이 아닌 List[Dog] 로 강제하고 싶다.

이런 필요성이 있을 때,  F-Bound  로 제한할 수 있다.

trait Animal[A <: Animal[A]] {
  def breed: List[A]
}

class Dog extends Animal[Dog] {
  override def breed: List[Dog] = ???
}

 

그런데 이는 아래처럼 개발자가 실수로 잘못 상속 받는 것을 막지는 못한다.

trait Animal[A <: Animal[A]] {
  def breed: List[A]
}

class Dog extends Animal[Dog] {
  override def breed: List[Dog] = ???
}

// Cat class 는 Animal[Cat] 을 상속받아야 하는데 Animal[Dog] 을 상속 받음
class Cat extends Animal[Dog] {
  override def breed: List[Dog] = ???
}

 

이것까지 강제하고 싶다면, self 타입 으로 제한한다.

// self 타입으로 제한
trait Animal[A <: Animal[A]] { self: A =>
  def breed: List[A]
}

class Dog extends Animal[Dog] {
  override def breed: List[Dog] = ???
}

// 컴파일 에러 !!!
class Cat extends Animal[Dog] {
  override def breed: List[Dog] = ???
}

 

지금까지 상속 + F-Bound + Self 타입으로 문제를 해결해 봤는데 복잡하다.

이럴 때 typeclass 를 이용해 해결하는 것은 매우 좋은 선택이 될 것 같다.