Обобщенное соответствие структурного типа в Scala

Меня интересует проблема соответствия определенного типа более общему структурному типу. Рассмотрим следующие примеры:

trait Sup

trait Sub extends Sup

type General = {
   def contra(o: Sub): Unit
   def co(): Sup
   def defaults(age: Int): Unit
   def defaults2(age: Int): Unit
   def defaults3(first: String): Unit
} 

trait Specific {
   def contra(o: Sup): Unit // doesn't conform
   def co(): Sub // conforms
   def defaults(age: Int, name: String = ""): Unit // doesn't conform
   def defaults2(name: String = "", age: Int = 0): Unit // doesn't conform
   def defaults3(first: String = "", last: String = ""): Unit // doesn't conform
}

В каждом из несоответствующих случаев вызов метода в General можно смело разрешать до соответствующего метода в Specific, Более интересный практический пример можно найти в этом вопросе:

trait Versionable[T] {
   self: { def copy(version: Int): T } =>
   val version = 0
   def incrementVersion = copy(version = version + 1)
}

case class Customer(name: String, override val version: Int) 
      extends Versionable[Customer] {
   def changeName(newName: String) = copy(name = newName)
}

Здесь, Заказчик copy Метод не соответствует сигнатуре в аннотации самообслуживания Versionable. Обратите внимание, однако, что если компилятор позволил, copy может быть вызван так же, как в Versionable.incrementVersion, Понятно, что актуальная подпись Клиента copy метод слишком специфичен для использования в Versionable, так как он несет несущественные знания о том, что можно name параметр.

Есть ли способы обойти эти ограничения? Есть ли причины, по которым такое обобщенное соответствие было бы плохой идеей?

1 ответ

Одна проблема заключается в том, что когда вы читаете этот код:

self: { def copy(version: Int): T }

вы не ожидаете, что имя параметра будет значимым, как это должно быть в этом примере:

case class Robot(number: Int, override val version: Int)
  extends Versionable[Robot]

РЕДАКТИРОВАТЬ: С другой стороны, что касается отсутствия параметров параметров для методов, вы можете сделать:

type General = { val contra: (Sub => Unit) }
class B { val contra = ((o:Sup) => println(o)) }
var b:General = new B
Другие вопросы по тегам