Что подразумевается под Scala зависимыми от пути типами?

Я слышал, что Scala имеет зависимые от пути типы. Это как-то связано с внутренними классами, но что это значит и почему меня это волнует?

Ответ 1

Мой любимый пример:

case class Board(length: Int, height: Int) {
  case class Coordinate(x: Int, y: Int) { 
    require(0 <= x && x < length && 0 <= y && y < height) 
  }
  val occupied = scala.collection.mutable.Set[Coordinate]()
}

val b1 = Board(20, 20)
val b2 = Board(30, 30)
val c1 = b1.Coordinate(15, 15)
val c2 = b2.Coordinate(25, 25)
b1.occupied += c1
b2.occupied += c2
// Next line doesn't compile
b1.occupied += c2

Итак, тип Coordinate зависит от экземпляра Board, из которого он был создан. Есть все, что может быть достигнуто с этим, предоставляя своего рода безопасность типов, которая зависит от ценностей, а не от типов.

Это может звучать как зависимые типы, но он более ограничен. Например, тип occupied зависит от значения Board. Выше, последняя строка не работает, потому что тип c2 равен b2.Coordinate, а тип occupied - Set[b1.Coordinate]. Обратите внимание, что можно использовать другой идентификатор с тем же типом b1, так что это не идентификатор b1, который связан с типом. Например, следующие работы:

val b3: b1.type = b1
val c3 = b3.Coordinate(10, 10)
b1.occupied += c3