Skip to content

Commit 9f10d60

Browse files
authored
Merge pull request scala/scala#8721 from eed3si9n/wip/migrate-ordering
Un-deprecate default floating point Orderings; issue migration warning instead under -Xmigration
2 parents 6af3fb2 + ba73064 commit 9f10d60

File tree

1 file changed

+81
-12
lines changed

1 file changed

+81
-12
lines changed

library/src/scala/math/Ordering.scala

Lines changed: 81 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,37 @@ 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 the default (implicit)
374+
* ordering on `Float` changed in 2.10.0 and 2.13.0.
375+
* Prior to Scala 2.10.0, the `Ordering` instance used 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 the `compare` method NOT compliant,
380+
* creating an internally inconsistent instance. IEEE 754 specifies that
381+
* `0.0F == -0.0F`. In addition, it requires all comparisons with `Float.NaN` return
382+
* `false` thus `0.0F < Float.NaN`, `0.0F > Float.NaN`, and
383+
* `Float.NaN == Float.NaN` all yield `false`, analogous `None` in `flatMap`.
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`, which retains
387+
* the IEEE 754 semantics from Scala 2.12.x, and `Ordering.Float.TotalOrdering`,
388+
* which brings back the `java.lang.Float.compare` semantics for all operations.
389+
* The default extends `TotalOrdering`.
390+
*
391+
* {{{
392+
* List(0.0F, 1.0F, 0.0F / 0.0F, -1.0F / 0.0F).sorted // List(-Infinity, 0.0, 1.0, NaN)
393+
* List(0.0F, 1.0F, 0.0F / 0.0F, -1.0F / 0.0F).min // -Infinity
394+
* implicitly[Ordering[Float]].lt(0.0F, 0.0F / 0.0F) // true
395+
* {
396+
* import Ordering.Float.IeeeOrdering
397+
* List(0.0F, 1.0F, 0.0F / 0.0F, -1.0F / 0.0F).sorted // List(-Infinity, 0.0, 1.0, NaN)
398+
* List(0.0F, 1.0F, 0.0F / 0.0F, -1.0F / 0.0F).min // NaN
399+
* implicitly[Ordering[Float]].lt(0.0F, 0.0F / 0.0F) // false
400+
* }
401+
* }}}
402+
*
403+
* @define floatOrdering Because the behavior of `Float`s specified by IEEE is
373404
* not consistent with a total ordering when dealing with
374405
* `NaN`, there are two orderings defined for `Float`:
375406
* `TotalOrdering`, which is consistent with a total
@@ -380,7 +411,7 @@ object Ordering extends LowPriorityOrderingImplicits {
380411
object Float {
381412
/** An ordering for `Float`s which is a fully consistent total ordering,
382413
* and treats `NaN` as larger than all other `Float` values; it behaves
383-
* the same as [[java.lang.Float#compare]].
414+
* the same as [[java.lang.Float.compare]].
384415
*
385416
* $floatOrdering
386417
*
@@ -401,7 +432,7 @@ object Ordering extends LowPriorityOrderingImplicits {
401432
* `NaN`.
402433
* - `min` and `max` are consistent with `math.min` and `math.max`, and
403434
* return `NaN` when called with `NaN` as either argument.
404-
* - `compare` behaves the same as [[java.lang.Float#compare]].
435+
* - `compare` behaves the same as [[java.lang.Float.compare]].
405436
*
406437
* $floatOrdering
407438
*
@@ -422,14 +453,48 @@ object Ordering extends LowPriorityOrderingImplicits {
422453
}
423454
implicit object IeeeOrdering extends IeeeOrdering
424455
}
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")
456+
@migration(
457+
" The default implicit ordering for floats now maintains consistency\n" +
458+
" between its `compare` method and its `lt`, `min`, `equiv`, etc., methods,\n" +
459+
" which means nonconforming to IEEE 754's behavior for -0.0F and NaN.\n" +
460+
" The sort order of floats remains the same, however, with NaN at the end.\n" +
461+
" Import Ordering.Float.IeeeOrdering to recover the previous behavior.\n" +
462+
" See also https://www.scala-lang.org/api/current/scala/math/Ordering$$Float$.html.", "2.13.0")
428463
implicit object DeprecatedFloatOrdering extends Float.TotalOrdering
429464

430465
/** `Ordering`s for `Double`s.
431466
*
432-
* @define doubleOrdering Because the behaviour of `Double`s specified by IEEE is
467+
* The behavior of the comparison operations provided by the default (implicit)
468+
* ordering on `Double` changed in 2.10.0 and 2.13.0.
469+
* Prior to Scala 2.10.0, the `Ordering` instance used semantics
470+
* consistent with `java.lang.Double.compare`.
471+
*
472+
* Scala 2.10.0 changed the implementation of `lt`, `equiv`, `min`, etc., to be
473+
* IEEE 754 compliant, while keeping the `compare` method NOT compliant,
474+
* creating an internally inconsistent instance. IEEE 754 specifies that
475+
* `0.0 == -0.0`. In addition, it requires all comparisons with `Double.NaN` return
476+
* `false` thus `0.0 < Double.NaN`, `0.0 > Double.NaN`, and
477+
* `Double.NaN == Double.NaN` all yield `false`, analogous `None` in `flatMap`.
478+
*
479+
* Recognizing the limitation of the IEEE 754 semantics in terms of ordering,
480+
* Scala 2.13.0 created two instances: `Ordering.Double.IeeeOrdering`, which retains
481+
* the IEEE 754 semantics from Scala 2.12.x, and `Ordering.Double.TotalOrdering`,
482+
* which brings back the `java.lang.Double.compare` semantics for all operations.
483+
* The default extends `TotalOrdering`.
484+
*
485+
* {{{
486+
* List(0.0, 1.0, 0.0 / 0.0, -1.0 / 0.0).sorted // List(-Infinity, 0.0, 1.0, NaN)
487+
* List(0.0, 1.0, 0.0 / 0.0, -1.0 / 0.0).min // -Infinity
488+
* implicitly[Ordering[Double]].lt(0.0, 0.0 / 0.0) // true
489+
* {
490+
* import Ordering.Double.IeeeOrdering
491+
* List(0.0, 1.0, 0.0 / 0.0, -1.0 / 0.0).sorted // List(-Infinity, 0.0, 1.0, NaN)
492+
* List(0.0, 1.0, 0.0 / 0.0, -1.0 / 0.0).min // NaN
493+
* implicitly[Ordering[Double]].lt(0.0, 0.0 / 0.0) // false
494+
* }
495+
* }}}
496+
*
497+
* @define doubleOrdering Because the behavior of `Double`s specified by IEEE is
433498
* not consistent with a total ordering when dealing with
434499
* `NaN`, there are two orderings defined for `Double`:
435500
* `TotalOrdering`, which is consistent with a total
@@ -440,7 +505,7 @@ object Ordering extends LowPriorityOrderingImplicits {
440505
object Double {
441506
/** An ordering for `Double`s which is a fully consistent total ordering,
442507
* and treats `NaN` as larger than all other `Double` values; it behaves
443-
* the same as [[java.lang.Double#compare]].
508+
* the same as [[java.lang.Double.compare]].
444509
*
445510
* $doubleOrdering
446511
*
@@ -461,7 +526,7 @@ object Ordering extends LowPriorityOrderingImplicits {
461526
* `NaN`.
462527
* - `min` and `max` are consistent with `math.min` and `math.max`, and
463528
* return `NaN` when called with `NaN` as either argument.
464-
* - `compare` behaves the same as [[java.lang.Double#compare]].
529+
* - `compare` behaves the same as [[java.lang.Double.compare]].
465530
*
466531
* $doubleOrdering
467532
*
@@ -482,9 +547,13 @@ object Ordering extends LowPriorityOrderingImplicits {
482547
}
483548
implicit object IeeeOrdering extends IeeeOrdering
484549
}
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")
550+
@migration(
551+
" The default implicit ordering for doubles now maintains consistency\n" +
552+
" between its `compare` method and its `lt`, `min`, `equiv`, etc., methods,\n" +
553+
" which means nonconforming to IEEE 754's behavior for -0.0 and NaN.\n" +
554+
" The sort order of doubles remains the same, however, with NaN at the end.\n" +
555+
" Import Ordering.Double.IeeeOrdering to recover the previous behavior.\n" +
556+
" See also https://www.scala-lang.org/api/current/scala/math/Ordering$$Double$.html.", "2.13.0")
488557
implicit object DeprecatedDoubleOrdering extends Double.TotalOrdering
489558

490559
trait BigIntOrdering extends Ordering[BigInt] {

0 commit comments

Comments
 (0)