Niedawno natknąłem się na termin "słaba zgodność" (w odpowiedzi na przepełnienie stosu użytkownika retronym na How to set up implicit conversion to allow arithmetic between numeric types?).Jaka jest koncepcja "słabej zgodności" w Scali?
Co to jest?
Niedawno natknąłem się na termin "słaba zgodność" (w odpowiedzi na przepełnienie stosu użytkownika retronym na How to set up implicit conversion to allow arithmetic between numeric types?).Jaka jest koncepcja "słabej zgodności" w Scali?
Co to jest?
3.5.3 Słaby Zgodności w niektórych sytuacjach Scala używa bardziej ogólny potwierdzeń, relację. Typ S słabo jest zgodny z typem T, napisany S <: w T , jeśli S <: T lub zarówno S i T są prymitywne typy numeryczne i S poprzedza T w następującej kolejności.
Słaby najmniej górna granica jest najmniej górna granica w odniesieniu do słabego zgodności.
Gdzie to jest używane? Po pierwsze, określa rodzaj if
wyrażeń:
typu ekspresji warunkowej jest słaby najmniej górna granica (§3.5.3) rodzajów E2 i E3
W Scala 2.7.x byłby to typ AnyVal
, najmniejszy limit związany z Int
i Double
. W wersji 2.8.x zapisuje się jako Double
.
scala> if (true) 1 else 1d
res0: Double = 1.0
Podobnie:
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>
Innym miejscem jest on stosowany jest w rodzaju wnioskowania:
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
A także do prostego poszerzenia numerycznej:
poszerzenie numeryczna. Jeżeli E ma pierwotnych numeryczny słabo zgodny (§3.5.3) do przewidywanego typu jest rozszerzony oczekiwanego typu za pomocą jednego z 6,26 to konwersja 97 liczbowe metody konwersji toShort, toChar, toInt , toLong, toFloat, toDouble zdefiniowane w § 12.2.1. typ oczekiwany to prymitywny numeryczny kod typu Bajt, krótki lub Char, a wyrażenie e jest całkowitym dosłownym dopasowaniem w zakresie w zakresie tego typu, jest konwertowane na ten sam literał tego samego.
scala> 1: Double
res10: Double = 1.0
UPDATE
Jak zauważył Daniel, spec jest złe, o których typy mają słabą zgodność. Zapytajmy sam kompilator:
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
Według Scala lang specyfikacji 2,8:
http://www.scala-lang.org/archives/downloads/distrib/files/nightly/pdfs/ScalaReference.pdf
3.5.3 Słaby zgodności
W niektórych sytuacjach Scala wykorzystuje bardziej genral potwierdzeń, związek. Typ S słabo jest zgodny z typem T, napisanym S <: w T, jeśli S <: T lub oba S i T są prymitywnymi numerami typy i S poprzedza T w następującym porządku.
Byte <: w krótkim
Byte <: bez znaków
Krótki <: w Int
Int <: w Longa
Długie <: w Float
Float <: w Pokój
Słaby kres górny jest najmniejsza górna granica w odniesieniu do słabej zgodności.
Jestem prawie pewny, że "Char" odpowiada również "Int". –
Aby zakończyć Sandor's answer, ta nowa funkcja w wersji 2.8 nadal jest pieczona (i naprawiana).
W this thread, Esser odkrywa przykry efekt uboczny:
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
Wydaje się interesujące, ponieważ w sposób dorozumiany znaleźć typ wynik jest
Double
a wynik jest 3,0.
Jeśli Pokój jest wyraźnie podane, wynik jest 3,33 ...
W this thread, Martin Odersky dodaje (21 czerwca):
Ci odkryli poważną niezamierzony efekt uboczny słaby zasady zgodności w przeciążeniu rozdzielczości.
Problem polegał na tym, że argumenty przeciążonych metod są wymagane do słabej zgodności, podczas gdy typ wyniku był wymagany, aby silnie się dostosować.to preferowane metody
Float => Float
dodawanie naInt
w stosunku do metodyInt => Int
jeśli typ rezultacie pływaka.
Starałem się być konserwatywny w mojej zmianie na słabą zgodność, ponieważ wymagałem słabej zgodności tylko tam, gdzie było to absolutnie konieczne.
Ale wydaje się, że bycie konserwatystą spowodowało problem, na który patrzymy!
I kolejny release Scala RC;)
Potwierdzone w this thread by Martin Odersky (June 22d):
Więc nie będzie RC7 z dotychczas trzy zmiany z RC6:
val x: Double = 10/3
da3.0
, a nie3.3333333
- to był regres byłem wspomnieć- [...]
- [...]
To wszystko. Naszym priorytetem jest teraz jak najszybsze wdrożenie 2.8, a jednocześnie unikanie naprawdę złych regresji, takich jak (1) powyżej.
Czas:
- Będziemy czekać jeszcze jeden tydzień, aby uzyskać opinię na temat RC6.
- Wypchniemy RC7 na początku przyszłego tygodnia.
Jeśli nie pojawią się żadne dalsze problemy, RC7 zmieni się w 2.8 w 10-14 dni po zwolnieniu.
(tak około 12 lipca, wierzę, ale to jest moje przypuszczenie sam;))
nota bene: https://lampsvn.epfl.ch/trac/scala/ticket/3594 – retronym