name - Diferente inferencia de tipos para `def` y` val` en Scala
scala by name parameter (2)
Observé una diferencia en la inferencia de tipo de Scala cuando se aplica a def
y val
.
Usando def
, puedo definir un método nullary abstracto const
devolviendo algún valor de tipo Int => Int
. Al implementar const
con una función literal, no necesito proporcionar un tipo de parámetro, ya que puede ser deducido por el compilador:
trait D {
def const: Int => Int
}
object D extends D {
def const = i => i + 1
}
Esto esta bien. (En el lado negativo, se está creando una nueva instancia de función para cada acceso a D.const
).
Ahora consideremos una construcción análoga usando val
:
trait V {
val const: Int => Int
}
object V extends V {
val const = i => i + 1
}
Esto no se compilará, fallando con
error: missing parameter type
val const = i => i + 1
^
¿Por qué?
A partir de Scala 2.9.1, esto es "como se especifica". Citando a Martin Odersky de SI-2742 :
Para los métodos, los tipos de retorno en los métodos abstractos heredados se toman como el tipo esperado del lado derecho. Para los valores no existe tal regla. Así que esta sería una solicitud de mejora de especificaciones, como lo veo.
El boleto es de baja prioridad y no ha cambiado desde su primera discusión a fines de 2009, por lo que parece poco probable que cambie pronto.
Si creas este código con la opción -Xprint all, verás que:
abstract trait V extends scala.AnyRef {
<stable> <accessor> def const: Int => Int
};
final object V extends java.lang.Object with V with ScalaObject {
def this(): object V = {
V.super.this();
()
};
private[this] val const: <error> => <error> = ((i: <error>) => i.+(1));
<stable> <accessor> def const: <error> => <error> = V.this.const
}
Así que el error se produce en la creación de val privado y accessor. El compilador intenta evaluar el valor afectado a la const de val antes de crear la const. de definición de acceso.
Si observa la constricción de val definida en el rasgo, verá que la creación de val privada fue deshabilitada porque es solo una definición para el descriptor de acceso de const.
Creo que el tipo de inferencia con la definición anterior (en rasgo o superclase) ocurrió solo cuando intentó crear el elemento de acceso, no para evaluar un valor.
Y para la última definición de const, el tipo solo se basa en el tipo de const const de [this] val privado: error => error