Почему чтение не объявлено ковариантным?

Почему функция play-json Reads не объявлена ​​ковариантной:

trait Reads[+A] 

Связанный сущность: https://gist.github.com/robertberry/9410272

Ковариация/контравариантность мешают имплицитам?

Или, необязательно, как написать экземпляр Reads для запечатанных признаков? https://gist.github.com/phadej/c60912802dc494c3212b

Ответ 1

Это может быть ковариантным, особенно если вы рассматриваете Reads[A] как более богатую форму JsValue => A.

Но.... имплицитность.

Reads[A] - это не просто a способ конвертировать из JsValue в A, это способ.

Итак, если бы мы имели

sealed trait Foo
case class Bar(a: Int)
case class Baz(b: Int)

Если вы определили a Reads[Bar], вы также (с ковариацией) имели бы Reads[Foo].

Это может быть немного странно.

object Foo {
  implicit reads: Reads[Foo] =
    implicitly[Reads[Bar]].orElse[implicitly[Reads[Baz]]]
}
object Bar {
  implicit reads = Json.reads[Bar] // {"a":0}
}
object Baz {
  implicit reads = Json.reads[Baz] // {"b":0}

  def blah(jsValue: JsValue): Foo = jsValue.as[Foo]
}
object Main {
  def blah(jsValue: JsValue): Foo = jsValue.as[Foo]
}

Что происходит в Baz.blah и Main.blah? Первый использует Baz.reads, а последний использует Foo.reads из-за (сложного) неявного порядка разрешения.

Это краевой случай, и я все еще думаю, что вы можете сделать хороший аргумент для ковариации, но он показывает разницу между "вещью, возможно, разобрать JSON в Foo" и "той, которая может анализировать JSON в все возможные Foo".

Ответ 2

Предположим, что Reads были ковариантными. У меня простая иерархия типов:

sealed trait Foo { def name: String }
case class Bar(name: String, i: Int) extends Foo
case class Baz(name: String, c: Char) extends Foo

И экземпляр Reads для одного из классов case:

import play.api.libs.functional.syntax._
import play.api.libs.json._

implicit val readsBar: Reads[Bar] = (
  (__ \ 'name).read[String] and (__ \ 'i).read[Int]
)(Bar.apply _)

Но Bar <: Foo, поэтому Reads[Bar] <: Reads[Foo], и это не имеет смысла - я ничего не сказал о том, как декодировать a Baz, поэтому у меня явно нет Reads[Foo].

Лучше может быть вопрос, почему Reads не является контравариантным.