Skip to content

Commit 27a8cc3

Browse files
committed
Un-deprecate default floating point Orderings, and change to migration
Fixes scala/bug#11844 Ref scala/bug#10511 Ref scala#6410 Ref scala#76 This change the deprecation of `DeprecatedDoubleOrdering` to a migration warning instead to avoid `List(1.0, -1.0).sorted` giving deprecation warning. This also provides some documentation on the ordering instances in Scaladoc.
1 parent ebe776e commit 27a8cc3

File tree

4 files changed

+105
-25
lines changed

4 files changed

+105
-25
lines changed

src/library/scala/math/Ordering.scala

Lines changed: 77 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package math
1616
import java.util.Comparator
1717

1818
import scala.language.implicitConversions
19+
import scala.annotation.migration
1920

2021
/** Ordering is a trait whose instances each represent a strategy for sorting
2122
* instances of a type.
@@ -369,7 +370,36 @@ object Ordering extends LowPriorityOrderingImplicits {
369370

370371
/** `Ordering`s for `Float`s.
371372
*
372-
* @define floatOrdering Because the behaviour of `Float`s specified by IEEE is
373+
* The behavior of the comparison operations provided by default (implicit)
374+
* ordering on `Float` has changed in 2.10.0 and 2.13.0.
375+
* Prior to Scala 2.10.0, the `Ordering` instance used the semantics
376+
* consistent with `java.lang.Float.compare`.
377+
*
378+
* Scala 2.10.0 changed the implementation of `lt`, `equiv`, `min` etc to be
379+
* IEEE 754 compliant, while keeping `compare` method NOT compliant,
380+
* creating an internally inconsistent instance. IEEE 754 specified that
381+
* `0.0F == -0.0F`. In addition, all comparisons with `Float.NaN` must return
382+
* `false` thus `0.0F < Float.NaN`, `0.0F > Float.NaN`, and
383+
* `Float.NaN == Float.NaN` all yield `false`, analogous to `None`.
384+
*
385+
* Recognizing the limitation of the IEEE 754 semantics in terms of ordering,
386+
* Scala 2.13.0 created two instances `Ordering.Float.IeeeOrdering` and
387+
* `Ordering.Float.TotalOrdering`, which brings back the `java.lang.Float.compare`
388+
* semantics for all operations. The default extends `TotalOrdering`.
389+
*
390+
* {{{
391+
* List(0.0F, 1.0F, 0.0F / 0.0F, -1.0F / 0.0F).sorted // List(-Infinity, 0.0, 1.0, NaN)
392+
* List(0.0F, 1.0F, 0.0F / 0.0F, -1.0F / 0.0F).min // -Infinity
393+
* implicitly[Ordering[Float]].lt(0.0F, 0.0F / 0.0F) // true
394+
* {
395+
* import Ordering.Float.IeeeOrdering
396+
* List(0.0F, 1.0F, 0.0F / 0.0F, -1.0F / 0.0F).sorted // List(-Infinity, 0.0, 1.0, NaN)
397+
* List(0.0F, 1.0F, 0.0F / 0.0F, -1.0F / 0.0F).min // NaN
398+
* implicitly[Ordering[Float]].lt(0.0F, 0.0F / 0.0F) // false
399+
* }
400+
* }}}
401+
*
402+
* @define floatOrdering Because the behavior of `Float`s specified by IEEE is
373403
* not consistent with a total ordering when dealing with
374404
* `NaN`, there are two orderings defined for `Float`:
375405
* `TotalOrdering`, which is consistent with a total
@@ -380,7 +410,7 @@ object Ordering extends LowPriorityOrderingImplicits {
380410
object Float {
381411
/** An ordering for `Float`s which is a fully consistent total ordering,
382412
* and treats `NaN` as larger than all other `Float` values; it behaves
383-
* the same as [[java.lang.Float#compare]].
413+
* the same as [[java.lang.Float.compare]].
384414
*
385415
* $floatOrdering
386416
*
@@ -401,7 +431,7 @@ object Ordering extends LowPriorityOrderingImplicits {
401431
* `NaN`.
402432
* - `min` and `max` are consistent with `math.min` and `math.max`, and
403433
* return `NaN` when called with `NaN` as either argument.
404-
* - `compare` behaves the same as [[java.lang.Float#compare]].
434+
* - `compare` behaves the same as [[java.lang.Float.compare]].
405435
*
406436
* $floatOrdering
407437
*
@@ -422,14 +452,46 @@ object Ordering extends LowPriorityOrderingImplicits {
422452
}
423453
implicit object IeeeOrdering extends IeeeOrdering
424454
}
425-
@deprecated("There are multiple ways to order Floats (Ordering.Float.TotalOrdering, " +
426-
"Ordering.Float.IeeeOrdering). Specify one by using a local import, assigning an implicit val, or passing it " +
427-
"explicitly. See their documentation for details.", since = "2.13.0")
455+
@migration(
456+
" The new ordering does not affect the sorting, placing NaN at the end.\n" +
457+
" However, methods such as `lt`, `min`, and `equiv` now match `compare`\n" +
458+
" instead of giving IEEE 754 behavior for -0.0F and NaN.\n" +
459+
" Import Ordering.Float.IeeeOrdering to retain the previous behavior.\n" +
460+
" See also https://www.scala-lang.org/api/current/scala/math/Ordering$$Float$.html", "2.13.0")
428461
implicit object DeprecatedFloatOrdering extends Float.TotalOrdering
429462

430463
/** `Ordering`s for `Double`s.
431464
*
432-
* @define doubleOrdering Because the behaviour of `Double`s specified by IEEE is
465+
* The behavior of the comparison operations provided by default (implicit)
466+
* ordering on `Double` has changed in 2.10.0 and 2.13.0.
467+
* Prior to Scala 2.10.0, the `Ordering` instance used the semantics
468+
* consistent with `java.lang.Double.compare`.
469+
*
470+
* Scala 2.10.0 changed the implementation of `lt`, `equiv`, `min` etc to be
471+
* IEEE 754 compliant, while keeping `compare` method NOT compliant,
472+
* creating an internally inconsistent instance. IEEE 754 specified that
473+
* `0.0 == -0.0`. In addition, all comparisons with `Double.NaN` must return
474+
* `false` thus `0.0 < Double.NaN`, `0.0 > Double.NaN`, and
475+
* `Double.NaN == Double.NaN` all yield `false`, analogous to `None`.
476+
*
477+
* Recognizing the limitation of the IEEE 754 semantics in terms of ordering,
478+
* Scala 2.13.0 created two instances `Ordering.Double.IeeeOrdering` and
479+
* `Ordering.Double.TotalOrdering`, which brings back the `java.lang.Double.compare`
480+
* semantics for all operations. The default extends `TotalOrdering`.
481+
*
482+
* {{{
483+
* List(0.0, 1.0, 0.0 / 0.0, -1.0 / 0.0).sorted // List(-Infinity, 0.0, 1.0, NaN)
484+
* List(0.0, 1.0, 0.0 / 0.0, -1.0 / 0.0).min // -Infinity
485+
* implicitly[Ordering[Double]].lt(0.0, 0.0 / 0.0) // true
486+
* {
487+
* import Ordering.Double.IeeeOrdering
488+
* List(0.0, 1.0, 0.0 / 0.0, -1.0 / 0.0).sorted // List(-Infinity, 0.0, 1.0, NaN)
489+
* List(0.0, 1.0, 0.0 / 0.0, -1.0 / 0.0).min // NaN
490+
* implicitly[Ordering[Double]].lt(0.0, 0.0 / 0.0) // false
491+
* }
492+
* }}}
493+
*
494+
* @define doubleOrdering Because the behavior of `Double`s specified by IEEE is
433495
* not consistent with a total ordering when dealing with
434496
* `NaN`, there are two orderings defined for `Double`:
435497
* `TotalOrdering`, which is consistent with a total
@@ -440,7 +502,7 @@ object Ordering extends LowPriorityOrderingImplicits {
440502
object Double {
441503
/** An ordering for `Double`s which is a fully consistent total ordering,
442504
* and treats `NaN` as larger than all other `Double` values; it behaves
443-
* the same as [[java.lang.Double#compare]].
505+
* the same as [[java.lang.Double.compare]].
444506
*
445507
* $doubleOrdering
446508
*
@@ -461,7 +523,7 @@ object Ordering extends LowPriorityOrderingImplicits {
461523
* `NaN`.
462524
* - `min` and `max` are consistent with `math.min` and `math.max`, and
463525
* return `NaN` when called with `NaN` as either argument.
464-
* - `compare` behaves the same as [[java.lang.Double#compare]].
526+
* - `compare` behaves the same as [[java.lang.Double.compare]].
465527
*
466528
* $doubleOrdering
467529
*
@@ -482,9 +544,12 @@ object Ordering extends LowPriorityOrderingImplicits {
482544
}
483545
implicit object IeeeOrdering extends IeeeOrdering
484546
}
485-
@deprecated("There are multiple ways to order Doubles (Ordering.Double.TotalOrdering, " +
486-
"Ordering.Double.IeeeOrdering). Specify one by using a local import, assigning an implicit val, or passing it " +
487-
"explicitly. See their documentation for details.", since = "2.13.0")
547+
@migration(
548+
" The new ordering does not affect the sorting, placing NaN at the end.\n" +
549+
" However, methods such as `lt`, `min`, and `equiv` now match `compare`\n" +
550+
" instead of giving IEEE 754 behavior for -0.0 and NaN.\n" +
551+
" Import Ordering.Double.IeeeOrdering to retain the previous behavior.\n" +
552+
" See also https://www.scala-lang.org/api/current/scala/math/Ordering$$Double$.html.", "2.13.0")
488553
implicit object DeprecatedDoubleOrdering extends Double.TotalOrdering
489554

490555
trait BigIntOrdering extends Ordering[BigInt] {
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
ordering-migration.scala:3: warning: object DeprecatedFloatOrdering in object Ordering has changed semantics in version 2.13.0:
2+
The new ordering does not affect the sorting, placing NaN at the end.
3+
However, methods such as `lt`, `min`, and `equiv` now match `compare`
4+
instead of giving IEEE 754 behavior for -0.0F and NaN.
5+
Import Ordering.Float.IeeeOrdering to retain the previous behavior.
6+
See also https://www.scala-lang.org/api/current/scala/math/Ordering$$Float$.html
7+
val f = Ordering[Float]
8+
^
9+
ordering-migration.scala:4: warning: object DeprecatedDoubleOrdering in object Ordering has changed semantics in version 2.13.0:
10+
The new ordering does not affect the sorting, placing NaN at the end.
11+
However, methods such as `lt`, `min`, and `equiv` now match `compare`
12+
instead of giving IEEE 754 behavior for -0.0 and NaN.
13+
Import Ordering.Double.IeeeOrdering to retain the previous behavior.
14+
See also https://www.scala-lang.org/api/current/scala/math/Ordering$$Double$.html.
15+
val d = Ordering[Double]
16+
^
17+
ordering-migration.scala:7: warning: object DeprecatedDoubleOrdering in object Ordering has changed semantics in version 2.13.0:
18+
The new ordering does not affect the sorting, placing NaN at the end.
19+
However, methods such as `lt`, `min`, and `equiv` now match `compare`
20+
instead of giving IEEE 754 behavior for -0.0 and NaN.
21+
Import Ordering.Double.IeeeOrdering to retain the previous behavior.
22+
See also https://www.scala-lang.org/api/current/scala/math/Ordering$$Double$.html.
23+
list.sorted
24+
^
25+
error: No warnings can be incurred under -Werror.
26+
3 warnings
27+
1 error

test/files/neg/t10511.scala renamed to test/files/neg/ordering-migration.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// scalac: -deprecation -Xfatal-warnings
1+
// scalac: -Xmigration -Werror
22
object Test {
33
val f = Ordering[Float]
44
val d = Ordering[Double]

test/files/neg/t10511.check

Lines changed: 0 additions & 12 deletions
This file was deleted.

0 commit comments

Comments
 (0)