#generics #scala #types #type-inference
#дженерики #scala #типы #вывод типа
Вопрос:
Рассмотрим этот код:
val foo = if(true)
new java.lang.Double(4)
else
new java.lang.Integer(4)
Выводимый тип для foo
равен:
Number with Comparable[_ >: Double with Integer <: Number with
Comparable[_ >: Double with Integer <: Number]]
Таким образом, в основном компилятор выполняет цикл по границам и прерывается после третьей рекурсии.
Почему недостаточно следующего?
Number with Comparable[_ >: Double with Integer <: Number]
Ответ №1:
Не ответ, а некоторые подсказки, которые неявно используются в REPL. Компилятор не считает, что типы одинаковы. Выводимый тип более специфичен:
// some type aliases to make reading easier
type Dx = java.lang.Double
type Ix = java.lang.Integer
// the type the compiler came up with:
type Inferred = Number with Comparable[
_ >: Dx with Ix <: Number with Comparable[_ >: Dx with Ix <: Number]]
// your type:
type Soc = Number with Comparable[_ >: Dx with Ix <: Number]
Проверяя, правильно ли я определил псевдонимы типов:
val d = new java.lang.Double(4)
val i = new java.lang.Integer(4)
val foo: Soc = if (true) d else i
// foo: Soc = 4.0
val foo: Inferred = if (true) d else i
// foo: Inferred = 4.0
Типы не совпадают:
implicitly[Soc =:= Inferred] // error
Ваш тип является супертипом предполагаемого типа:
implicitly[Inferred <:< Soc] // ok
implicitly[Soc <:< Inferred] // error
Итак, согласно компилятору, он придумал более конкретный тип, что было бы правильным решением. Обратите внимание, что вариант использования может быть воссоздан следующим образом:
class N // like java.lang.Number
trait C[T] // like Comparable
class I extends N with C[I] // like java.lang.Integer
class D extends N with C[D] // like java.lang.Double
type DI = N with C[_ >: D with I <: N with C[_ >: D with I <: N]]
// DI is like the type inferred
type DI_SOC = N with C[_ >: D with I <: N] // your type
val foo: DI = if (true) new D else new I // ok
val foo: DI_SOC = if (true) new D else new I // ok
implicitly[DI =:= DI_SOC] // error
implicitly[DI <:< DI_SOC] // DI_SOC super type of DI
implicitly[DI_SOC <:< DI] // error
Итак, мне интересно, можем ли мы создать класс, который является DI_SOC
, но не a DI
, который иллюстрировал бы, что DI
и DI_SOC
не являются одними и теми же типами, и ваш тип не является наименьшей верхней границей.
Хорошо, после того, как я ненадолго выйду за компьютер, а затем повторю попытку. Вот класс, который является DI_SOC
, но не DI
:
class A extends N with C[N]
implicitly[A <:< DI_SOC] // ok
implicitly[A <:< DI] // error
Применяется к исходному варианту использования:
class Ax extends Number with Comparable[Number] {
def doubleValue() = 0d
def floatValue() = 0f
def intValue() = 0
def longValue() = 0L
def compareTo(n: Number) = 0
}
implicitly[Ax <:< Soc] // ok
implicitly[Ax <:< Inferred] // error
Следовательно, типы Soc
и Inferred
не совпадают и Ax
доказывают, что Number with Comparable[_ >: Double with Integer <: Number]
это не наименьшая верхняя граница…
Другими словами, между ними есть некоторое пространство Double with Integer <: ? <: Number
, но не так много между Double with Integer <: ? <: Number with Comparable[_ >: Double with Integer <: Number]