Search code examples
scalascala-3match-types

Why were match types added to scala3 despite method uoverloading fulfilling the same role?


I was just watching a video by rockthejvm that can be found here. My only issue is that it fails to address if match types can do anything method overloading cannot? Is there anything that match types do better than method overloading? It seems they are just a less extensible version of method overloading.

Any wisdom would be greatly appreciated.


Solution

  • This example from the documentation:

    type LeafElem[X] = X match
      case String => Char
      case Array[t] => LeafElem[t]
      case Iterable[t] => LeafElem[t]
      case AnyVal => X
    
    def leafElem[X](x: X): LeafElem[X] = x match
      case x: String      => x.charAt(0)
      case x: Array[t]    => leafElem(x(9))
      case x: Iterable[t] => leafElem(x.head)
      case x: AnyVal      => x
    

    can't be translated to overloading. The non-recursive cases are easy:

    def leafElem(x: String): Char = x.charAt(0)
    def leafElem(x: AnyVal): AnyVal = x
    

    but what would you do with arrays? If you write

    def leafElem[T](x: Array[T]): ??? = leafElem(x(9))
    

    then:

    1. without match types you can't write the return type (and you have to, because it's an overloaded method);
    2. even if you could, you can't express the constraint "T must be the parameter type of a leafElem overload" required for the body to compile.

    Or consider this non-recursive example

    type Elem[X] = X match
      case String => Char
      case Array[t] => t
      case Iterable[t] => t
    
    def elem[X](x: X): Elem[X] = x match { /* doesn't really matter */ }
    

    With match types you can write

    def mapElems[X](seq: Seq[X]): Seq[Elem[X]] = seq.map(elem(_))
    

    If you had overloaded elem methods for separate cases, mapElems wouldn't compile (and again you couldn't write its return type if it did).