¿Cuál es el concepto de "conformidad débil" en Scala?
scala-2.8 (3)
3.5.3 Conformidad débil En algunas situaciones, Scala utiliza una relación de conformidad más general. Un tipo S se ajusta débilmente a un tipo T, escrito S <: w T, si S <: T o S y T son tipos de números primitivos y S precede a T en el siguiente ordenamiento.
- Byte <: w Corto
- Byte <: w carácter
- Corto <: w Int
- Int <: w Long
- Largo <: w Flotador
- Flotante <: w Doble
Un límite inferior mínimo débil es un límite inferior superior con respecto a la conformidad débil.
¿Dónde se usa esto? Por un lado, determina el tipo de expresiones if
:
El tipo de expresión condicional es el límite inferior débil (§3.5.3) de los tipos de e2 y e3
En Scala 2.7.x, esto sería del tipo AnyVal
, el límite mínimo de Int
y Double
. En 2.8.x, se escribe como Double
.
scala> if (true) 1 else 1d
res0: Double = 1.0
Similar:
scala> try { 1 } catch { case _ => 1.0 }
res2: Double = 1.0
scala> (new {}: Any) match { case 1 => 1; case _ => 1.0 }
res6: Double = 1.0
scala> def pf[R](pf: PartialFunction[Any, R]): PartialFunction[Any, R] = pf
pf: [R](pf: PartialFunction[Any,R])PartialFunction[Any,R]
scala> pf { case 1 => 1; case _ => 1d }
res4: PartialFunction[Any,Double] = <function1>
Otro lugar donde se usa es en inferencia de tipo:
scala> def foo[A](a1: A, a2: A): A = a1
foo: [A](a1: A,a2: A)A
scala> foo(1, 1d)
res8: Double = 1.0
scala> def foos[A](as: A*): A = as.head
foos: [A](as: A*)A
scala> foos(1, 1d)
res9: Double = 1.0
Y también para la ampliación numérica simple:
Ampliación Numérica. Si e tiene un tipo de número primitivo que se adapta débilmente (§3.5.3) al tipo esperado, se amplía al tipo esperado usando uno de los 6.26 métodos de conversión numérica de Conversiones Implícitas 97 a Cortar, aChar, aInt, aLong, aFloat, aDouble definido en §12.2.1. el tipo esperado es un tipo numérico primitivo Byte, Short o Char, y la expresión e es un ajuste literal entero en el rango de ese tipo, se convierte al mismo literal en ese tipo.
scala> 1: Double
res10: Double = 1.0
ACTUALIZAR
Como lo señaló Daniel, la especificación es errónea acerca de qué tipos tienen una conformidad débil. Preguntemos al compilador mismo:
scala> :power
** Power User mode enabled - BEEP BOOP **
** scala.tools.nsc._ has been imported **
** New vals! Try repl, global, power **
** New cmds! :help to discover them **
** New defs! Type power.<tab> to reveal **
scala> settings.maxPrintString = 10000
scala> import global.definitions._
import global.definitions._
scala> (for{c1 <- ScalaValueClasses;
c2 <- ScalaValueClasses
isNSC = isNumericSubClass(c1, c2)
if isNSC
} yield ("isNumericSubClass (%s, %s) = %b" format (c1, c2, isNSC))).mkString("/n")
res5: String =
isNumericSubClass (class Byte, class Byte) = true
isNumericSubClass (class Byte, class Short) = true
isNumericSubClass (class Byte, class Int) = true
isNumericSubClass (class Byte, class Long) = true
isNumericSubClass (class Byte, class Float) = true
isNumericSubClass (class Byte, class Double) = true
isNumericSubClass (class Short, class Short) = true
isNumericSubClass (class Short, class Int) = true
isNumericSubClass (class Short, class Long) = true
isNumericSubClass (class Short, class Float) = true
isNumericSubClass (class Short, class Double) = true
isNumericSubClass (class Int, class Int) = true
isNumericSubClass (class Int, class Long) = true
isNumericSubClass (class Int, class Float) = true
isNumericSubClass (class Int, class Double) = true
isNumericSubClass (class Long, class Long) = true
isNumericSubClass (class Long, class Float) = true
isNumericSubClass (class Long, class Double) = true
isNumericSubClass (class Char, class Int) = true
isNumericSubClass (class Char, class Long) = true
isNumericSubClass (class Char, class Char) = true
isNumericSubClass (class Char, class Float) = true
isNumericSubClass (class Char, class Double) = true
isNumericSubClass (class Float, class Float) = true
isNumericSubClass (class Float, class Double) = true
isNumericSubClass (class Double, class Double) = true
Hace poco me encontré con el término "Conformidad débil" (en la respuesta de los retronym usuario de Stack Overflow a ¿Cómo configurar la conversión implícita para permitir la aritmética entre tipos numéricos? ).
¿Qué es?
Para completar la respuesta de Sandor , esa nueva característica en 2.8 aún se está cocinando (y arreglando).
En este hilo , Esser descubre un efecto secundario desagradable:
scala> val a= 10
a: Int = 10
scala> val b= 3
b: Int = 3
scala> if (b!=0) a/b else Double.NaN
res0: Double = 3.0
scala> def div1(a: Int, b: Int) = if (b!=0) a/b else Double.NaN
div1: (a: Int,b: Int)Double
scala> def div2(a: Int, b: Int): Double = if (b!=0) a/b else Double.NaN
div2: (a: Int,b: Int)Double
scala> div1(10,3)
res1: Double = 3.0
scala> div2(10,3)
res2: Double = 3.3333333333333335
Parece interesante, porque el tipo de resultado encontrado implícitamente es
Double
y el resultado es 3.0.
Si se da Doble explícitamente, el resultado es 3.33 ...
En este hilo , Martin Odersky agrega (21 de junio):
ha descubierto un serio efecto secundario no deseado de las reglas de conformidad débiles en la resolución de sobrecarga.
El problema era que los argumentos de los métodos sobrecargados se requieren para ajustarse débilmente, mientras que el tipo de resultado fue requerido para ajustarse fuertemente.Esto favoreció el método de adición
Float => Float
en unInt
sobre el métodoInt => Int
si el tipo de resultado era Float.
Trataba de ser conservador en mi cambio a una conformidad débil en el sentido de que requería una conformidad débil solo cuando parecía absolutamente necesario.
¡Pero ahora parece que ser conservador causó el problema que estamos viendo!
Y aún otro lanzamiento de Scala RC;)
Confirmado en este hilo por Martin Odersky (22 de junio) :
Así que habrá un RC7 con hasta ahora tres cambios de RC6:
val x: Double = 10/3
dará3.0
, no3.3333333
, esa fue la regresión que mencioné- [...]
- [...]
Eso es. Nuestras prioridades ahora son desplegar 2.8 lo más rápido posible, y al mismo tiempo evitar las regresiones realmente malas como la (1) anterior.
Línea de tiempo:
- Esperaremos una semana más para recibir comentarios sobre RC6.
- Vamos a sacar RC7 a principios de la próxima semana.
Si no aparecen más problemas, RC7 se convertirá en 2.8 final 10-14 días después de su lanzamiento.
(Así que alrededor del 12 de julio, creo, pero esta suposición es solo mía;))
Según Scala lang spec 2.8:
http://www.scala-lang.org/archives/downloads/distrib/files/nightly/pdfs/ScalaReference.pdf
3.5.3 Conformidad débil
En algunas situaciones Scala usa una relación de conformidad más genral. Un tipo S se ajusta débilmente a un tipo T, escrito S <: w T, si S <: T o S y T son tipos de números primitivos y S precede a T en el siguiente ordenamiento.
Byte <: w Corto
Byte <: w carácter
Corto <: w Int
Int <: w Long
Largo <: w Flotador
Flotante <: w Doble
Un límite inferior mínimo débil es un límite inferior superior con respecto a la conformidad débil.