Тип аргумента контравариантного метода

Вики Contravariant_method_argument_type говорит, что метод переопределения имеет правило подтипа в качестве типа функции, но нет языка, кроме одного поддерживающего контравариантного типа аргумента. Я также не в состоянии придумать какую-либо идею о пользе, чтобы использовать это.

пример:

class AnimalShelter {
    Animal getAnimalForAdoption() {      ...        }         
    void putAnimal(Animal animal) {      ...        }   
}

class CatShelter extends AnimalShelter {
    @Overriding        
    Cat getAnimalForAdoption() {  return new Cat();    }        
    @Overriding                    
    void putAnimal(Object animal) {      …        }     
}

Мой вопрос:

  1. Является ли контравариантный тип аргумента переопределяющего метода полезным? если да, где это?
  2. Является ли метод функцией? Почему Scala имеет разные правила для типа функции и типа переопределенного метода?

2 ответа

Решение

Является ли контравариантный тип аргумента переопределяющего метода полезным? если да, где это?

Пример переведен из документации Sather:

interface Carnivore {
  void eat(Meat food);
}

interface Herbivore {
  void eat(Plant food);
}

interface Omnivore extends Carnivore, Herbivore {
  // overrides both above eat methods,
  // since Meat and Plant are subtypes of Food
  void eat(Food food);
}

Является ли метод функцией?

В скале? Нет, но его можно преобразовать в функцию.

Почему Scala имеет разные правила для типа функции и типа переопределенного метода?

Потому что переопределение типов методов должно соответствовать правилам JVM. Это может быть сделано путем создания методов моста (в случае выше, добавление методов eat(Plant) а также eat(Meat) который просто позвоните eat(Food)), аналогично тому, как реализован ковариантный тип возвращаемого значения, но это усложнит язык без особой выгоды.

Я также могу добавить один пример из набора инструментов Spray, в частности черта Marshaller. В общем, вы можете думать о Marshallers как о функции с преобразованием некоторой сущности типа T в HttpEntity (для ответа http), но с некоторыми внутренними хитростями, так что на самом деле это реализовано как (T, Context) => Unit, где HttpEntity генерируется этим Contenxt, Во всяком случае, если вы посмотрите на его объявление, вы увидите, что это тип T находится в контравариантном положении:

trait Marshaller[-T] {
  def apply(value: T, ctx: MarshallingContext)
}

Семантически вы можете думать об этом с точки зрения простой функции, которая возвращает Unit, И здесь противоречивость естественна. Допустим, у вас есть простая иерархия:

sealed trait ServerInfo {
  def data: DataTime
}

case class ServiceStatus(status: String, data: DateTime = DateTime.now) extends ServerInfo

С помощью этого маршаллера:

val serverInfoMarshaller: Marshaller[ServerInfo] = ???
val serverStatusMarshaller: Marshaller[ServerStatus] = ???

И у вас есть функция, которая возвращает этот статус:

def response(data: ServiceStatus, marshaller: Marshaller[ServiceStatus]): Unit = ???

Но поскольку маршаллер противоречив, вы также можете использовать не только serverStatusMarshaller: Marshaller[ServerStatus], но также serverInfoMarshaller: Marshaller[ServerInfo] потому что он также знает, как сериализовать ServerStatus в правильный ответ для пользователя.

Другие вопросы по тегам