Recentemente ho incontrato il termine "Conformità debole" (in Stack Overflow user retronym's risposta a How to set up implicit conversion to allow arithmetic between numeric types?).Qual è il concetto di "debole conformità" in Scala?
Che cos'è?
Recentemente ho incontrato il termine "Conformità debole" (in Stack Overflow user retronym's risposta a How to set up implicit conversion to allow arithmetic between numeric types?).Qual è il concetto di "debole conformità" in Scala?
Che cos'è?
3.5.3 Conformità debole in alcune situazioni Scala utilizza un più generale conformità relazione. Un tipo S debolmente conforme a un tipo T, S scritta <: w T , se S <: T o entrambi S e T sono tipi di numero primitivi e S precede T nel seguente ordine.
Una debole estremo superiore è un limite almeno superiore rispetto alla debole conformità.
Dove viene utilizzato? Per prima cosa, si determina il tipo di if
espressioni:
Il tipo dell'espressione condizionale è debole estremo superiore (§3.5.3) dei tipi di e2 e e3
In Scala 2.7.x, questo sarebbe di tipo AnyVal
, il limite minimo di Int
e Double
. In 2.8.x, viene impostato come Double
.
scala> if (true) 1 else 1d
res0: Double = 1.0
Analogamente:
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>
altro luogo esso viene utilizzato in inferenza:
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
Ed anche per semplice ampliamento numerico:
Widening numerico. Se e ha una primitiva tipo numero conforme debolmente (§3.5.3) per il tipo previsto, è allargato al tipo previsto utilizzando uno dei 6,26 Conversioni implicite 97 metodi di conversione numerica toShort, tochar, Toint , toLong, toFloat, toDouble definito in §12.2.1. tipo previsto è un tipo numerico primitivo Byte, Short o Char e l'espressione e è un adattamento letterale intero nell'intervallo di quel tipo, viene convertito nello stesso valore letterale in quel tipo.
scala> 1: Double
res10: Double = 1.0
UPDATE
Come sottolineato da Daniel, la specifica è sbagliato su quali tipi hanno la conformità debole. Chiediamo al compilatore stesso:
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
Secondo Scala Lang spec 2.8:
http://www.scala-lang.org/archives/downloads/distrib/files/nightly/pdfs/ScalaReference.pdf
3.5.3 Debole Conformance
In alcune situazioni Scala usa un rapporto di conformità più Genral. Un tipo S debolmente è conforme a un tipo T, scritto S <: w T, se S <: T o entrambi S e T sono numeri primitivi tipi e S precede T nel seguente ordine.
Byte <: w Breve
Byte <: w carattere
Breve <: w Int
Int <: w lungo
lungo <: w Float
Float <: w doppio
Un debole estremo superiore è un minimo superiore rispetto alla debole conformità.
Sono quasi sicuro che 'Char' è conforme anche a' Int'. –
Per completare Sandor's answer, quella nuova funzione in 2.8 è ancora in fase di cottura (e fissa).
In this thread, Esser scopre un brutto effetto collaterale:
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
sembra interessante, in quanto il tipo di risultato implicitamente trovato è
Double
e il risultato è 3,0.
Se doppio è esplicitamente dato, il risultato è 3.33 ...
In this thread, Martin Odersky aggiunge (21 giugno):
voi hanno scoperto una seria involontario effetto collaterale dei deboli regole di conformità nella risoluzione di sovraccarico.
Il problema era che gli argomenti dei metodi sovraccaricati sono richiesti per conformarsi debolmente, mentre il tipo di risultato era richiesto per conformarsi con forza.Questo favorito il metodo
Float => Float
inoltre su unInt
rispetto al metodoInt => Int
se il tipo risultato era galleggiante.
Stavo cercando di essere prudente nel mio passaggio a una debole conformità, in quanto richiedevo una debole conformità solo dove sembrava assolutamente necessario.
Ma ora sembra che essere prudenti abbia causato il problema che stiamo guardando!
E ancora un altro rilascio Scala RC;)
confermata in this thread by Martin Odersky (June 22d):
Quindi ci sarà un RC7 con finora tre cambiamenti rispetto RC6:
val x: Double = 10/3
darà3.0
, non3.3333333
- che era la regressione accennavo- [...]
- [...]
Questo è tutto. Le nostre priorità ora sono di distribuirle il più rapidamente possibile e allo stesso tempo evitare regressioni davvero negative come (1) sopra.
Timeline:
- Vi aspettiamo una settimana in più per ottenere un feedback sulla RC6.
- Spegneremo RC7 all'inizio della prossima settimana.
Se non si verificano ulteriori problemi RC7 si trasformerebbe quindi in 2,8 finale 10-14 giorni dopo il rilascio.
(quindi intorno al 12 luglio, credo, ma questo è solo mia congettura;))
nota bene: https://lampsvn.epfl.ch/trac/scala/ticket/3594 – retronym