Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Un-deprecate default floating point Orderings; issue migration warning instead under -Xmigration #8721

Merged
merged 1 commit into from Feb 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
93 changes: 81 additions & 12 deletions src/library/scala/math/Ordering.scala
Expand Up @@ -16,6 +16,7 @@ package math
import java.util.Comparator

import scala.language.implicitConversions
import scala.annotation.migration

/** Ordering is a trait whose instances each represent a strategy for sorting
* instances of a type.
Expand Down Expand Up @@ -369,7 +370,37 @@ object Ordering extends LowPriorityOrderingImplicits {

/** `Ordering`s for `Float`s.
*
* @define floatOrdering Because the behaviour of `Float`s specified by IEEE is
* The behavior of the comparison operations provided by the default (implicit)
* ordering on `Float` changed in 2.10.0 and 2.13.0.
* Prior to Scala 2.10.0, the `Ordering` instance used semantics
* consistent with `java.lang.Float.compare`.
*
* Scala 2.10.0 changed the implementation of `lt`, `equiv`, `min`, etc., to be
* IEEE 754 compliant, while keeping the `compare` method NOT compliant,
* creating an internally inconsistent instance. IEEE 754 specifies that
* `0.0F == -0.0F`. In addition, it requires all comparisons with `Float.NaN` return
* `false` thus `0.0F < Float.NaN`, `0.0F > Float.NaN`, and
* `Float.NaN == Float.NaN` all yield `false`, analogous `None` in `flatMap`.
*
* Recognizing the limitation of the IEEE 754 semantics in terms of ordering,
* Scala 2.13.0 created two instances: `Ordering.Float.IeeeOrdering`, which retains
* the IEEE 754 semantics from Scala 2.12.x, and `Ordering.Float.TotalOrdering`,
* which brings back the `java.lang.Float.compare` semantics for all operations.
* The default extends `TotalOrdering`.
*
* {{{
* List(0.0F, 1.0F, 0.0F / 0.0F, -1.0F / 0.0F).sorted // List(-Infinity, 0.0, 1.0, NaN)
* List(0.0F, 1.0F, 0.0F / 0.0F, -1.0F / 0.0F).min // -Infinity
* implicitly[Ordering[Float]].lt(0.0F, 0.0F / 0.0F) // true
* {
* import Ordering.Float.IeeeOrdering
* List(0.0F, 1.0F, 0.0F / 0.0F, -1.0F / 0.0F).sorted // List(-Infinity, 0.0, 1.0, NaN)
* List(0.0F, 1.0F, 0.0F / 0.0F, -1.0F / 0.0F).min // NaN
* implicitly[Ordering[Float]].lt(0.0F, 0.0F / 0.0F) // false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like it! 👍

* }
* }}}
*
* @define floatOrdering Because the behavior of `Float`s specified by IEEE is
* not consistent with a total ordering when dealing with
* `NaN`, there are two orderings defined for `Float`:
* `TotalOrdering`, which is consistent with a total
Expand All @@ -380,7 +411,7 @@ object Ordering extends LowPriorityOrderingImplicits {
object Float {
/** An ordering for `Float`s which is a fully consistent total ordering,
* and treats `NaN` as larger than all other `Float` values; it behaves
* the same as [[java.lang.Float#compare]].
* the same as [[java.lang.Float.compare]].
*
* $floatOrdering
*
Expand All @@ -401,7 +432,7 @@ object Ordering extends LowPriorityOrderingImplicits {
* `NaN`.
* - `min` and `max` are consistent with `math.min` and `math.max`, and
* return `NaN` when called with `NaN` as either argument.
* - `compare` behaves the same as [[java.lang.Float#compare]].
* - `compare` behaves the same as [[java.lang.Float.compare]].
*
* $floatOrdering
*
Expand All @@ -422,14 +453,48 @@ object Ordering extends LowPriorityOrderingImplicits {
}
implicit object IeeeOrdering extends IeeeOrdering
}
@deprecated("There are multiple ways to order Floats (Ordering.Float.TotalOrdering, " +
"Ordering.Float.IeeeOrdering). Specify one by using a local import, assigning an implicit val, or passing it " +
"explicitly. See their documentation for details.", since = "2.13.0")
@migration(
" The default implicit ordering for floats now maintains consistency\n" +
" between its `compare` method and its `lt`, `min`, `equiv`, etc., methods,\n" +
" which means nonconforming to IEEE 754's behavior for -0.0F and NaN.\n" +
" The sort order of floats remains the same, however, with NaN at the end.\n" +
" Import Ordering.Float.IeeeOrdering to recover the previous behavior.\n" +
" See also https://www.scala-lang.org/api/current/scala/math/Ordering$$Float$.html.", "2.13.0")
implicit object DeprecatedFloatOrdering extends Float.TotalOrdering

/** `Ordering`s for `Double`s.
*
* @define doubleOrdering Because the behaviour of `Double`s specified by IEEE is
* The behavior of the comparison operations provided by the default (implicit)
* ordering on `Double` changed in 2.10.0 and 2.13.0.
* Prior to Scala 2.10.0, the `Ordering` instance used semantics
* consistent with `java.lang.Double.compare`.
*
* Scala 2.10.0 changed the implementation of `lt`, `equiv`, `min`, etc., to be
* IEEE 754 compliant, while keeping the `compare` method NOT compliant,
* creating an internally inconsistent instance. IEEE 754 specifies that
* `0.0 == -0.0`. In addition, it requires all comparisons with `Double.NaN` return
* `false` thus `0.0 < Double.NaN`, `0.0 > Double.NaN`, and
* `Double.NaN == Double.NaN` all yield `false`, analogous `None` in `flatMap`.
*
* Recognizing the limitation of the IEEE 754 semantics in terms of ordering,
* Scala 2.13.0 created two instances: `Ordering.Double.IeeeOrdering`, which retains
* the IEEE 754 semantics from Scala 2.12.x, and `Ordering.Double.TotalOrdering`,
* which brings back the `java.lang.Double.compare` semantics for all operations.
* The default extends `TotalOrdering`.
*
* {{{
* List(0.0, 1.0, 0.0 / 0.0, -1.0 / 0.0).sorted // List(-Infinity, 0.0, 1.0, NaN)
* List(0.0, 1.0, 0.0 / 0.0, -1.0 / 0.0).min // -Infinity
* implicitly[Ordering[Double]].lt(0.0, 0.0 / 0.0) // true
* {
* import Ordering.Double.IeeeOrdering
* List(0.0, 1.0, 0.0 / 0.0, -1.0 / 0.0).sorted // List(-Infinity, 0.0, 1.0, NaN)
* List(0.0, 1.0, 0.0 / 0.0, -1.0 / 0.0).min // NaN
* implicitly[Ordering[Double]].lt(0.0, 0.0 / 0.0) // false
* }
* }}}
*
* @define doubleOrdering Because the behavior of `Double`s specified by IEEE is
* not consistent with a total ordering when dealing with
* `NaN`, there are two orderings defined for `Double`:
* `TotalOrdering`, which is consistent with a total
Expand All @@ -440,7 +505,7 @@ object Ordering extends LowPriorityOrderingImplicits {
object Double {
/** An ordering for `Double`s which is a fully consistent total ordering,
* and treats `NaN` as larger than all other `Double` values; it behaves
* the same as [[java.lang.Double#compare]].
* the same as [[java.lang.Double.compare]].
*
* $doubleOrdering
*
Expand All @@ -461,7 +526,7 @@ object Ordering extends LowPriorityOrderingImplicits {
* `NaN`.
* - `min` and `max` are consistent with `math.min` and `math.max`, and
* return `NaN` when called with `NaN` as either argument.
* - `compare` behaves the same as [[java.lang.Double#compare]].
* - `compare` behaves the same as [[java.lang.Double.compare]].
*
* $doubleOrdering
*
Expand All @@ -482,9 +547,13 @@ object Ordering extends LowPriorityOrderingImplicits {
}
implicit object IeeeOrdering extends IeeeOrdering
}
@deprecated("There are multiple ways to order Doubles (Ordering.Double.TotalOrdering, " +
"Ordering.Double.IeeeOrdering). Specify one by using a local import, assigning an implicit val, or passing it " +
"explicitly. See their documentation for details.", since = "2.13.0")
@migration(
" The default implicit ordering for doubles now maintains consistency\n" +
" between its `compare` method and its `lt`, `min`, `equiv`, etc., methods,\n" +
" which means nonconforming to IEEE 754's behavior for -0.0 and NaN.\n" +
" The sort order of doubles remains the same, however, with NaN at the end.\n" +
" Import Ordering.Double.IeeeOrdering to recover the previous behavior.\n" +
" See also https://www.scala-lang.org/api/current/scala/math/Ordering$$Double$.html.", "2.13.0")
implicit object DeprecatedDoubleOrdering extends Double.TotalOrdering

trait BigIntOrdering extends Ordering[BigInt] {
Expand Down
30 changes: 30 additions & 0 deletions test/files/neg/ordering-migration.check
@@ -0,0 +1,30 @@
ordering-migration.scala:3: warning: object DeprecatedFloatOrdering in object Ordering has changed semantics in version 2.13.0:
The default implicit ordering for floats now maintains consistency
between its `compare` method and its `lt`, `min`, `equiv`, etc., methods,
which means nonconforming to IEEE 754's behavior for -0.0F and NaN.
The sort order of floats remains the same, however, with NaN at the end.
Import Ordering.Float.IeeeOrdering to recover the previous behavior.
See also https://www.scala-lang.org/api/current/scala/math/Ordering$$Float$.html.
val f = Ordering[Float]
^
ordering-migration.scala:4: warning: object DeprecatedDoubleOrdering in object Ordering has changed semantics in version 2.13.0:
The default implicit ordering for doubles now maintains consistency
between its `compare` method and its `lt`, `min`, `equiv`, etc., methods,
which means nonconforming to IEEE 754's behavior for -0.0 and NaN.
The sort order of doubles remains the same, however, with NaN at the end.
Import Ordering.Double.IeeeOrdering to recover the previous behavior.
See also https://www.scala-lang.org/api/current/scala/math/Ordering$$Double$.html.
val d = Ordering[Double]
^
ordering-migration.scala:7: warning: object DeprecatedDoubleOrdering in object Ordering has changed semantics in version 2.13.0:
The default implicit ordering for doubles now maintains consistency
between its `compare` method and its `lt`, `min`, `equiv`, etc., methods,
which means nonconforming to IEEE 754's behavior for -0.0 and NaN.
The sort order of doubles remains the same, however, with NaN at the end.
Import Ordering.Double.IeeeOrdering to recover the previous behavior.
See also https://www.scala-lang.org/api/current/scala/math/Ordering$$Double$.html.
list.sorted
^
error: No warnings can be incurred under -Werror.
3 warnings
1 error
@@ -1,4 +1,4 @@
// scalac: -deprecation -Xfatal-warnings
// scalac: -Xmigration -Werror
dwijnand marked this conversation as resolved.
Show resolved Hide resolved
object Test {
val f = Ordering[Float]
val d = Ordering[Double]
Expand Down
12 changes: 0 additions & 12 deletions test/files/neg/t10511.check

This file was deleted.