diff --git a/library/src/scala/Boolean.scala b/library/src/scala/Boolean.scala index 5df9184b5e30..0e373ca537c9 100644 --- a/library/src/scala/Boolean.scala +++ b/library/src/scala/Boolean.scala @@ -138,5 +138,15 @@ object Boolean extends AnyValCompanion { /** The String representation of the scala.Boolean companion object. */ override def toString = "object scala.Boolean" + extension (self: Boolean) { + + /** Compares `this` to `that` according to the standard total ordering. + * + * Returns: + * - a positive value if `this` is `true` and `that` is `false` + * - a negative value if `this` is `false` and `that` is `true` + * - `0` if `this == that` + */ + def compare(that: Boolean): Int = java.lang.Boolean.compare(self, that) + } } - diff --git a/library/src/scala/Byte.scala b/library/src/scala/Byte.scala index c1f0e81f746b..5d9c411ac984 100644 --- a/library/src/scala/Byte.scala +++ b/library/src/scala/Byte.scala @@ -18,6 +18,8 @@ package scala import scala.language.`2.13` +import scala.collection.immutable.NumericRange + /** `Byte`, a 8-bit signed integer (equivalent to Java's `byte` primitive type) is a * subtype of [[scala.AnyVal]]. Instances of `Byte` are not * represented by an object in the underlying runtime system. @@ -485,5 +487,89 @@ object Byte extends AnyValCompanion { implicit def byte2long(x: Byte): Long = x.toLong implicit def byte2float(x: Byte): Float = x.toFloat implicit def byte2double(x: Byte): Double = x.toDouble -} + extension (self: Byte) { + /** Returns `'''true'''` if this number has no decimal component. + * Always `'''true'''` for `Byte`. + */ + @deprecated("isWhole on Byte is always true", "2.12.15") + def isWhole: Boolean = true + + /** Returns `true` iff this is within the + * range of [[scala.Char]] MinValue and MaxValue; otherwise returns `false`. + */ + def isValidChar: Boolean = self >= 0 + + /** Returns `true` iff this is within the + * range of [[scala.Byte]] MinValue and MaxValue; otherwise returns `false`. + */ + @deprecated("isValidByte on Byte is always true", "3.8.0") + def isValidByte: Boolean = true + + /** Returns `true` iff this is within the + * range of [[scala.Short]] MinValue and MaxValue; otherwise returns `false`. + */ + @deprecated("isValidShort on Byte is always true", "3.8.0") + def isValidShort: Boolean = true + + /** Returns `true` iff this is within the + * range of [[scala.Int]] MinValue and MaxValue; otherwise returns `false`. + */ + @deprecated("isValidInt on Byte is always true", "3.8.0") + def isValidInt: Boolean = true + + /** Returns the absolute value of `this`. */ + def abs: Byte = java.lang.Math.abs(self.toInt).toByte + + /** Returns `this` if `this > that` or `that` otherwise. */ + def max(that: Byte): Byte = java.lang.Math.max(self.toInt, that.toInt).toByte + + /** Returns `this` if `this < that` or `that` otherwise. */ + def min(that: Byte): Byte = java.lang.Math.min(self.toInt, that.toInt).toByte + + /** Returns the sign of `this`. + * + * `0` if `this == 0`, `-1` if `this < 0` and `1` if `this > 0`. + */ + def sign: Byte = java.lang.Integer.signum(self.toInt).toByte + + /** Returns the signum of `this`. */ + @deprecated("use `sign` method instead", since = "2.13.0") + def signum: Int = self.sign.toInt + + /** Compares `this` to `that` according to the standard total ordering. + * + * Returns: + * - a positive value if `this > that` + * - a negative value if `this < that` + * - `0` if `this == that` + */ + def compare(that: Byte): Int = java.lang.Byte.compare(self, that) + + /** A [[scala.collection.immutable.NumericRange]] from `this` up to but not including `end`. + * + * @param end The final bound of the range to make. + */ + def until(end: Byte): NumericRange.Exclusive[Byte] = NumericRange(self, end, 1) + + /** A [[scala.collection.immutable.NumericRange]] from `this` up to but not including `end`. + * + * @param end The final bound of the range to make. + * @param step The number to increase by for each step of the range. + */ + def until(end: Byte, step: Byte): NumericRange.Exclusive[Byte] = NumericRange(self, end, step) + + /** A [[scala.collection.immutable.NumericRange]] from `this` up to and including `end`. + * + * @param end The final bound of the range to make. + */ + def to(end: Byte): NumericRange.Inclusive[Byte] = NumericRange.inclusive(self, end, 1) + + /** A [[scala.collection.immutable.NumericRange]] from `this` up to and including `end`. + * + * @param end The final bound of the range to make. + * @param step The number to increase by for each step of the range. + */ + def to(end: Byte, step: Byte): NumericRange.Inclusive[Byte] = NumericRange.inclusive(self, end, step) + } +} diff --git a/library/src/scala/Char.scala b/library/src/scala/Char.scala index 06a6e186901b..7b1a3fcb9bd1 100644 --- a/library/src/scala/Char.scala +++ b/library/src/scala/Char.scala @@ -18,6 +18,8 @@ package scala import scala.language.`2.13` +import scala.collection.immutable.NumericRange + /** `Char`, a 16-bit unsigned integer (equivalent to Java's `char` primitive type) is a * subtype of [[scala.AnyVal]]. Instances of `Char` are not * represented by an object in the underlying runtime system. @@ -484,5 +486,122 @@ object Char extends AnyValCompanion { implicit def char2long(x: Char): Long = x.toLong implicit def char2float(x: Char): Float = x.toFloat implicit def char2double(x: Char): Double = x.toDouble -} + extension (self: Char) { + + /** Returns `'''true'''` if this number has no decimal component. + * Always `'''true'''` for `RichInt`. + */ + @deprecated("isWhole on Char is always true", "2.12.15") + def isWhole: Boolean = true + + /** Returns `true` iff this is within the + * range of [[scala.Char]] MinValue and MaxValue; otherwise returns `false`. + */ + @deprecated("isValidChar on Char is always true", "3.8.0") + def isValidChar: Boolean = true + + /** Returns `true` iff this is within the + * range of [[scala.Byte]] MinValue and MaxValue; otherwise returns `false`. + */ + def isValidByte: Boolean = self.toInt <= Byte.MaxValue.toInt + + /** Returns `true` iff this is within the + * range of [[scala.Short]] MinValue and MaxValue; otherwise returns `false`. + */ + def isValidShort: Boolean = self.toInt <= Short.MaxValue.toInt + + /** Returns `true` iff this is within the + * range of [[scala.Int]] MinValue and MaxValue; otherwise returns `false`. + */ + @deprecated("isValidInt on Char is always true", "3.8.0") + def isValidInt: Boolean = true + + /** Returns the absolute value of `this`. */ + @deprecated("Char's are never negative; abs is redundant and can be removed", since = "3.8.0") + def abs: Char = self + + /** Returns `this` if `this > that` or `that` otherwise. */ + def max(that: Char): Char = java.lang.Math.max(self.toInt, that.toInt).toChar + + /** Returns `this` if `this < that` or `that` otherwise. */ + def min(that: Char): Char = java.lang.Math.min(self.toInt, that.toInt).toChar + + /** Returns the sign of `this`. + * + * zero if the argument is zero, -zero if the argument is -zero, + * one if the argument is greater than zero, -one if the argument is less than zero, + * and NaN if the argument is NaN where applicable. + */ + @deprecated("since Char's are never negative, compare to '\\u0000' instead", since = "3.8.0") + def sign: Char = java.lang.Integer.signum(self.toInt).toChar + + /** Returns the signum of `this`. */ + @deprecated("use `sign` method instead", since = "2.13.0") + def signum: Int = self.sign + + /** Compares `this` to `that` according to the standard total ordering. + * + * Returns: + * - a positive value if `this > that` + * - a negative value if `this < that` + * - `0` if `this == that` + */ + def compare(that: Char): Int = java.lang.Character.compare(self, that) + + /** A [[scala.collection.immutable.NumericRange]] from `this` up to but not including `end`. + * + * @param end The final bound of the range to make. + */ + def until(end: Char): NumericRange.Exclusive[Char] = NumericRange(self, end, '\u0001') + + /** A [[scala.collection.immutable.NumericRange]] from `this` up to but not including `end`. + * + * @param end The final bound of the range to make. + * @param step The number to increase by for each step of the range. + */ + def until(end: Char, step: Char): NumericRange.Exclusive[Char] = NumericRange(self, end, step) + + /** A [[scala.collection.immutable.NumericRange]] from `this` up to and including `end`. + * + * @param end The final bound of the range to make. + */ + def to(end: Char): NumericRange.Inclusive[Char] = NumericRange.inclusive(self, end, '\u0001') + + /** A [[scala.collection.immutable.NumericRange]] from `this` up to and including `end`. + * + * @param end The final bound of the range to make. + * @param step The number to increase by for each step of the range. + */ + def to(end: Char, step: Char): NumericRange.Inclusive[Char] = NumericRange.inclusive(self, end, step) + + def asDigit: Int = Character.digit(self, Character.MAX_RADIX) + + def isControl: Boolean = Character.isISOControl(self) + def isDigit: Boolean = Character.isDigit(self) + def isLetter: Boolean = Character.isLetter(self) + def isLetterOrDigit: Boolean = Character.isLetterOrDigit(self) + def isWhitespace: Boolean = Character.isWhitespace(self) + def isSpaceChar: Boolean = Character.isSpaceChar(self) + def isHighSurrogate: Boolean = Character.isHighSurrogate(self) + def isLowSurrogate: Boolean = Character.isLowSurrogate(self) + def isSurrogate: Boolean = isHighSurrogate || isLowSurrogate + def isUnicodeIdentifierStart: Boolean = Character.isUnicodeIdentifierStart(self) + def isUnicodeIdentifierPart: Boolean = Character.isUnicodeIdentifierPart(self) + def isIdentifierIgnorable: Boolean = Character.isIdentifierIgnorable(self) + def isMirrored: Boolean = Character.isMirrored(self) + + def isLower: Boolean = Character.isLowerCase(self) + def isUpper: Boolean = Character.isUpperCase(self) + def isTitleCase: Boolean = Character.isTitleCase(self) + + def toLower: Char = Character.toLowerCase(self) + def toUpper: Char = Character.toUpperCase(self) + def toTitleCase: Char = Character.toTitleCase(self) + + def getType: Int = Character.getType(self) + def getNumericValue: Int = Character.getNumericValue(self) + def getDirectionality: Byte = Character.getDirectionality(self) + def reverseBytes: Char = Character.reverseBytes(self) + } +} diff --git a/library/src/scala/Double.scala b/library/src/scala/Double.scala index 57e99999198b..42bae1c279eb 100644 --- a/library/src/scala/Double.scala +++ b/library/src/scala/Double.scala @@ -18,6 +18,8 @@ package scala import scala.language.`2.13` +import scala.collection.immutable.NumericRange + /** `Double`, a 64-bit IEEE-754 floating point number (equivalent to Java's `double` primitive type) is a * subtype of [[scala.AnyVal]]. Instances of `Double` are not * represented by an object in the underlying runtime system. @@ -253,5 +255,103 @@ object Double extends AnyValCompanion { /** The String representation of the scala.Double companion object. */ override def toString = "object scala.Double" -} + extension (self: Double) { + /** Returns `'''true'''` if this number is finite and has no decimal component. */ + def isWhole: Boolean = { + val l = self.toLong + l.toDouble == self || l == Long.MaxValue && self < Double.PositiveInfinity || l == Long.MinValue && self > Double.NegativeInfinity + } + + /** Returns `true` iff this has a zero fractional part, and is within the + * range of [[scala.Char]] MinValue and MaxValue; otherwise returns `false`. + */ + def isValidChar: Boolean = self.toChar.toDouble == self + + /** Returns `true` iff this has a zero fractional part, and is within the + * range of [[scala.Byte]] MinValue and MaxValue; otherwise returns `false`. + */ + def isValidByte: Boolean = self.toByte.toDouble == self + + /** Returns `true` iff this has a zero fractional part, and is within the + * range of [[scala.Short]] MinValue and MaxValue; otherwise returns `false`. + */ + def isValidShort: Boolean = self.toShort.toDouble == self + + /** Returns `true` iff this has a zero fractional part, and is within the + * range of [[scala.Int]] MinValue and MaxValue; otherwise returns `false`. + */ + def isValidInt: Boolean = self.toInt.toDouble == self + + /** Returns `true` iff `this` is a `NaN` value. */ + def isNaN: Boolean = java.lang.Double.isNaN(self) + + /** Returns `true` iff `this` is `PositiveInfinity` or `NegativeInfinity`. */ + def isInfinity: Boolean = java.lang.Double.isInfinite(self) + + /** Returns `true` iff `this` is a finite value, i.e., not an infinity nor `NaN`. */ + def isFinite: Boolean = java.lang.Double.isFinite(self) + + /** Returns `true` iff `this` is `PositiveInfinity`. */ + def isPosInfinity: Boolean = Double.PositiveInfinity == self + + /** Returns `true` iff `this` is `NegativeInfinity`. */ + def isNegInfinity: Boolean = Double.NegativeInfinity == self + + /** Returns the absolute value of `this`. */ + def abs: Double = java.lang.Math.abs(self) + + /** Returns `this` if `this > that` or `that` otherwise. */ + def max(that: Double): Double = java.lang.Math.max(self, that) + + /** Returns `this` if `this < that` or `that` otherwise. */ + def min(that: Double): Double = java.lang.Math.min(self, that) + + /** Returns the sign of `this`. + * + * - `1.0` if `this > 0.0`; + * - `-1.0` if `this < 0.0`; + * - `this` otherwise (for zeros and `NaN`). + */ + def sign: Double = java.lang.Math.signum(self) + + /** Returns the signum of `this`. */ + @deprecated("signum does not handle -0.0 or Double.NaN; use `sign` method instead", since = "2.13.0") + def signum: Int = self.sign.toInt + + /** Returns the closest `Long` to `this`. */ + def round: Long = java.lang.Math.round(self) + + /** Returns the smallest integer greater or equal to `this`. */ + def ceil: Double = java.lang.Math.ceil(self) + + /** Returns the largest integer smaller or equal to `this`. */ + def floor: Double = java.lang.Math.floor(self) + + /** Converts an angle measured in degrees to an approximately equivalent + * angle measured in radians. + * + * @return the measurement of the angle x in radians. + */ + def toRadians: Double = java.lang.Math.toRadians(self) + + /** Converts an angle measured in radians to an approximately equivalent + * angle measured in degrees. + * @return the measurement of the angle x in degrees. + */ + def toDegrees: Double = java.lang.Math.toDegrees(self) + + /** Compares `this` to `that` according to the standard total ordering. + * + * Returns: + * - a positive value if `this > that` + * - a negative value if `this < that` + * - `0` if `this == that` + * + * Special cases for this method: + * - `0.0` is considered greater than `-0.0` + * - `NaN` is considered greater than all other values, but equal to itself + */ + def compare(that: Double): Int = java.lang.Double.compare(self, that) + } +} diff --git a/library/src/scala/Float.scala b/library/src/scala/Float.scala index 1f8b00886258..975e6fbfb00b 100644 --- a/library/src/scala/Float.scala +++ b/library/src/scala/Float.scala @@ -256,5 +256,104 @@ object Float extends AnyValCompanion { /** Language mandated coercions from Float to "wider" types. */ import scala.language.implicitConversions implicit def float2double(x: Float): Double = x.toDouble -} + extension (self: Float) { + /** Returns `'''true'''` if this number is finite and has no decimal component. */ + def isWhole: Boolean = { + val i = self.toInt + i.toFloat == self || i == Int.MaxValue && self < Float.PositiveInfinity || i == Int.MinValue && self > Float.NegativeInfinity + } + + /** Returns `true` iff this has a zero fractional part, and is within the + * range of [[scala.Char]] MinValue and MaxValue; otherwise returns `false`. + */ + def isValidChar: Boolean = self.toChar.toFloat == self + + /** Returns `true` iff this has a zero fractional part, and is within the + * range of [[scala.Byte]] MinValue and MaxValue; otherwise returns `false`. + */ + def isValidByte: Boolean = self.toByte.toFloat == self + + /** Returns `true` iff this has a zero fractional part, and is within the + * range of [[scala.Short]] MinValue and MaxValue; otherwise returns `false`. + */ + def isValidShort: Boolean = self.toShort.toFloat == self + + /** Returns `true` iff this has a zero fractional part, and is within the + * range of [[scala.Int]] MinValue and MaxValue; otherwise returns `false`. + */ + def isValidInt: Boolean = + self.toInt.toFloat == self && self >= Int.MinValue.toFloat && self < -Int.MinValue.toFloat + + /** Returns `true` iff `this` is a `NaN` value. */ + def isNaN: Boolean = java.lang.Float.isNaN(self) + + /** Returns `true` iff `this` is `PositiveInfinity` or `NegativeInfinity`. */ + def isInfinity: Boolean = java.lang.Float.isInfinite(self) + + /** Returns `true` iff `this` is a finite value, i.e., not an infinity nor `NaN`. */ + def isFinite: Boolean = java.lang.Float.isFinite(self) + + /** Returns `true` iff `this` is `PositiveInfinity`. */ + def isPosInfinity: Boolean = Float.PositiveInfinity == self + + /** Returns `true` iff `this` is `NegativeInfinity`. */ + def isNegInfinity: Boolean = Float.NegativeInfinity == self + + /** Returns the absolute value of `this`. */ + def abs: Float = java.lang.Math.abs(self) + + /** Returns `this` if `this > that` or `that` otherwise. */ + def max(that: Float): Float = java.lang.Math.max(self, that) + + /** Returns `this` if `this < that` or `that` otherwise. */ + def min(that: Float): Float = java.lang.Math.min(self, that) + + /** Returns the sign of `this`. + * + * - `1.0f` if `this > 0.0f`; + * - `-1.0f` if `this < 0.0f`; + * - `this` otherwise (for zeros and `NaN`). + */ + def sign: Float = java.lang.Math.signum(self) + + /** Returns the signum of `this`. */ + @deprecated("signum does not handle -0.0f or Double.NaN; use `sign` method instead", since = "2.13.0") + def signum: Int = self.sign.toInt + + /** Returns the closest `Int` to `this`. */ + def round: Int = java.lang.Math.round(self) + + /** Returns the smallest integer greater or equal to `this`. */ + def ceil: Float = java.lang.Math.ceil(self.toDouble).toFloat + + /** Returns the largest integer smaller or equal to `this`. */ + def floor: Float = java.lang.Math.floor(self.toDouble).toFloat + + /** Converts an angle measured in degrees to an approximately equivalent + * angle measured in radians. + * + * @return the measurement of the angle x in radians. + */ + def toRadians: Float = java.lang.Math.toRadians(self.toDouble).toFloat + + /** Converts an angle measured in radians to an approximately equivalent + * angle measured in degrees. + * @return the measurement of the angle x in degrees. + */ + def toDegrees: Float = java.lang.Math.toDegrees(self.toDouble).toFloat + + /** Compares `this` to `that` according to the standard total ordering. + * + * Returns: + * - a positive value if `this > that` + * - a negative value if `this < that` + * - `0` if `this == that` + * + * Special cases for this method: + * - `0.0` is considered greater than `-0.0` + * - `NaN` is considered greater than all other values, but equal to itself + */ + def compare(that: Float): Int = java.lang.Float.compare(self, that) + } +} diff --git a/library/src/scala/Int.scala b/library/src/scala/Int.scala index a3fff7e991da..28e40a26de19 100644 --- a/library/src/scala/Int.scala +++ b/library/src/scala/Int.scala @@ -484,5 +484,101 @@ object Int extends AnyValCompanion { implicit def int2float(x: Int): Float = x.toFloat implicit def int2long(x: Int): Long = x.toLong implicit def int2double(x: Int): Double = x.toDouble -} + extension (self: Int) { + /** Returns `'''true'''` if this number has no decimal component. + * Always `'''true'''` for `Int`. + */ + @deprecated("isWhole on Int is always true", "2.12.15") + def isWhole: Boolean = true + + /** Returns `true` iff this is within the + * range of [[scala.Char]] MinValue and MaxValue; otherwise returns `false`. + */ + def isValidChar: Boolean = self.toChar.toInt == self + + /** Returns `true` iff this is within the + * range of [[scala.Byte]] MinValue and MaxValue; otherwise returns `false`. + */ + def isValidByte: Boolean = self.toByte.toInt == self + + /** Returns `true` iff this is within the + * range of [[scala.Short]] MinValue and MaxValue; otherwise returns `false`. + */ + def isValidShort: Boolean = self.toShort.toInt == self + + /** Returns `true` iff this is within the + * range of [[scala.Int]] MinValue and MaxValue; otherwise returns `false`. + */ + @deprecated("isValidInt on Int is always true", "3.8.0") + def isValidInt: Boolean = true + + /** Returns `true` iff this is within the + * range of [[scala.Long]] MinValue and MaxValue; otherwise returns `false`. + */ + @deprecated("isValidLong on Int is always true", "3.8.0") + def isValidLong: Boolean = true + + /** Returns the absolute value of `this`. */ + def abs: Int = java.lang.Math.abs(self) + + /** Returns `this` if `this > that` or `that` otherwise. */ + def max(that: Int): Int = java.lang.Math.max(self, that) + + /** Returns `this` if `this < that` or `that` otherwise. */ + def min(that: Int): Int = java.lang.Math.min(self, that) + + /** Returns the sign of `this`. + * + * `0` if `this == 0`, `-1` if `this < 0` and `1` if `this > 0`. + */ + def sign: Int = java.lang.Integer.signum(self) + + /** Returns the signum of `this`. */ + @deprecated("use `sign` method instead", since = "2.13.0") + def signum: Int = self.sign + + /** There is no reason to round an `Int`, but this method is provided to avoid accidental loss of precision from a detour through `Float`. */ + @deprecated("this is an integer type; there is no reason to round it. Perhaps you meant to call this on a floating-point value?", "2.11.0") + def round: Int = self + + /** Compares `this` to `that` according to the standard total ordering. + * + * Returns: + * - a positive value if `this > that` + * - a negative value if `this < that` + * - `0` if `this == that` + */ + def compare(that: Int): Int = java.lang.Integer.compare(self, that) + + def toBinaryString: String = java.lang.Integer.toBinaryString(self) + def toHexString: String = java.lang.Integer.toHexString(self) + def toOctalString: String = java.lang.Integer.toOctalString(self) + + /** A [[scala.collection.immutable.Range]] from `this` up to but not including `end`. + * + * @param end The final bound of the range to make. + */ + def until(end: Int): Range = Range(self, end) + + /** A [[scala.collection.immutable.Range]] from `this` up to but not including `end`. + * + * @param end The final bound of the range to make. + * @param step The number to increase by for each step of the range. + */ + def until(end: Int, step: Int): Range = Range(self, end, step) + + /** A [[scala.collection.immutable.Range]] from `this` up to and including `end`. + * + * @param end The final bound of the range to make. + */ + def to(end: Int): Range.Inclusive = Range.inclusive(self, end) + + /** A [[scala.collection.immutable.Range]] from `this` up to and including `end`. + * + * @param end The final bound of the range to make. + * @param step The number to increase by for each step of the range. + */ + def to(end: Int, step: Int): Range.Inclusive = Range.inclusive(self, end, step) + } +} diff --git a/library/src/scala/Long.scala b/library/src/scala/Long.scala index 2561c1ec74c2..6d1e1f29ea6b 100644 --- a/library/src/scala/Long.scala +++ b/library/src/scala/Long.scala @@ -18,6 +18,8 @@ package scala import scala.language.`2.13` +import scala.collection.immutable.NumericRange + /** `Long`, a 64-bit signed integer (equivalent to Java's `long` primitive type) is a * subtype of [[scala.AnyVal]]. Instances of `Long` are not * represented by an object in the underlying runtime system. @@ -481,5 +483,100 @@ object Long extends AnyValCompanion { implicit def long2float(x: Long): Float = x.toFloat @deprecated("Implicit conversion from Long to Double is dangerous because it loses precision. Write `.toDouble` instead.", "2.13.1") implicit def long2double(x: Long): Double = x.toDouble -} + extension (self: Long) { + /** Returns `'''true'''` if this number has no decimal component. + * Always `'''true'''` for `Long`. + */ + @deprecated("isWhole on Long is always true", "2.12.15") + def isWhole: Boolean = true + + /** Returns `true` iff this is within the + * range of [[scala.Char]] MinValue and MaxValue; otherwise returns `false`. + */ + def isValidChar: Boolean = self.toChar.toLong == self + + /** Returns `true` iff this is within the + * range of [[scala.Byte]] MinValue and MaxValue; otherwise returns `false`. + */ + def isValidByte: Boolean = self.toByte.toLong == self + + /** Returns `true` iff this is within the + * range of [[scala.Short]] MinValue and MaxValue; otherwise returns `false`. + */ + def isValidShort: Boolean = self.toShort.toLong == self + + /** Returns `true` iff this is within the + * range of [[scala.Int]] MinValue and MaxValue; otherwise returns `false`. + */ + def isValidInt: Boolean = self.toShort.toLong == self + + /** Returns `true` iff this is within the + * range of [[scala.Long]] MinValue and MaxValue; otherwise returns `false`. + */ + @deprecated("isValidLong on Long is always true", "3.8.0") + def isValidLong: Boolean = true + + /** Returns the absolute value of `this`. */ + def abs: Long = java.lang.Math.abs(self) + + /** Returns `this` if `this > that` or `that` otherwise. */ + def max(that: Long): Long = java.lang.Math.max(self, that) + + /** Returns `this` if `this < that` or `that` otherwise. */ + def min(that: Long): Long = java.lang.Math.min(self, that) + + /** Returns the sign of `this`. + * + * `0` if `this == 0`, `-1` if `this < 0` and `1` if `this > 0`. + */ + def sign: Long = java.lang.Long.signum(self) + + /** Returns the signum of `this`. */ + @deprecated("use `sign` method instead", since = "2.13.0") + def signum: Int = self.sign.toInt + + /** There is no reason to round an `Int`, but this method is provided to avoid accidental loss of precision from a detour through `Double`. */ + @deprecated("this is an integer type; there is no reason to round it. Perhaps you meant to call this on a floating-point value?", "2.11.0") + def round: Long = self + + /** Compares `this` to `that` according to the standard total ordering. + * + * Returns: + * - a positive value if `this > that` + * - a negative value if `this < that` + * - `0` if `this == that` + */ + def compare(that: Long): Int = java.lang.Long.compare(self, that) + + def toBinaryString: String = java.lang.Long.toBinaryString(self) + def toHexString: String = java.lang.Long.toHexString(self) + def toOctalString: String = java.lang.Long.toOctalString(self) + + /** A [[scala.collection.immutable.NumericRange]] from `this` up to but not including `end`. + * + * @param end The final bound of the range to make. + */ + def until(end: Long): NumericRange.Exclusive[Long] = NumericRange(self, end, 1L) + + /** A [[scala.collection.immutable.NumericRange]] from `this` up to but not including `end`. + * + * @param end The final bound of the range to make. + * @param step The number to increase by for each step of the range. + */ + def until(end: Long, step: Long): NumericRange.Exclusive[Long] = NumericRange(self, end, step) + + /** A [[scala.collection.immutable.NumericRange]] from `this` up to and including `end`. + * + * @param end The final bound of the range to make. + */ + def to(end: Long): NumericRange.Inclusive[Long] = NumericRange.inclusive(self, end, 1L) + + /** A [[scala.collection.immutable.NumericRange]] from `this` up to and including `end`. + * + * @param end The final bound of the range to make. + * @param step The number to increase by for each step of the range. + */ + def to(end: Long, step: Long): NumericRange.Inclusive[Long] = NumericRange.inclusive(self, end, step) + } +} diff --git a/library/src/scala/Predef.scala b/library/src/scala/Predef.scala index 7e2c2f09666b..b546d21acdd5 100644 --- a/library/src/scala/Predef.scala +++ b/library/src/scala/Predef.scala @@ -286,12 +286,12 @@ object Predef extends LowPriorityImplicits { to be available at runtime. To achieve this, we keep the Scala 3 signature publicly available. We rely on the fact that it is `inline` and will not be visible in the bytecode. - To add the required Scala 2 ones, we define the `scala2Assert`, we use: - - `@targetName` to swap the name in the generated code to `assert` + To add the required Scala 2 ones, we define the `scala2Assert`, we use: + - `@targetName` to swap the name in the generated code to `assert` - `@publicInBinary` to make it available during runtime. As such, we would successfully hijack the definitions of `assert` such as: - At compile time, we would have the definitions of `assert` - - At runtime, the definitions of `scala2Assert` as `assert` + - At runtime, the definitions of `scala2Assert` as `assert` NOTE: Tasty-Reader in Scala 2 will have to learn about this swapping if we are to allow loading the full Scala 3 library by it. */ @@ -426,7 +426,7 @@ object Predef extends LowPriorityImplicits { @inline def formatted(fmtstr: String): String = fmtstr format self } - /** Injects String concatenation operator `+` to any classes. + /** Injects String concatenation operator `+` to any classes. * @group implicit-classes-any */ @(deprecated @companionMethod)("Implicit injection of + is deprecated. Convert to String to call +", "2.13.0") @@ -638,24 +638,23 @@ object Predef extends LowPriorityImplicits { private[scala] abstract class LowPriorityImplicits extends LowPriorityImplicits2 { import mutable.ArraySeq - /** We prefer the java.lang.* boxed types to these wrappers in - * any potential conflicts. Conflicts do exist because the wrappers - * need to implement ScalaNumber in order to have a symmetric equals - * method, but that implies implementing java.lang.Number as well. - * - * Note - these are inlined because they are value classes, but - * the call to xxxWrapper is not eliminated even though it does nothing. - * Even inlined, every call site does a no-op retrieval of Predef's MODULE$ - * because maybe loading Predef has side effects! - */ - @inline implicit def byteWrapper(x: Byte): runtime.RichByte = new runtime.RichByte(x) - @inline implicit def shortWrapper(x: Short): runtime.RichShort = new runtime.RichShort(x) - @inline implicit def intWrapper(x: Int): runtime.RichInt = new runtime.RichInt(x) - @inline implicit def charWrapper(c: Char): runtime.RichChar = new runtime.RichChar(c) - @inline implicit def longWrapper(x: Long): runtime.RichLong = new runtime.RichLong(x) - @inline implicit def floatWrapper(x: Float): runtime.RichFloat = new runtime.RichFloat(x) - @inline implicit def doubleWrapper(x: Double): runtime.RichDouble = new runtime.RichDouble(x) - @inline implicit def booleanWrapper(x: Boolean): runtime.RichBoolean = new runtime.RichBoolean(x) + // Deprecated conversions to runtime.Rich* classes; these methods used to be `implicit` + @deprecated("use the extension methods available on primitive types instead", since = "3.8.0") + @inline def byteWrapper(x: Byte): runtime.RichByte = new runtime.RichByte(x) + @deprecated("use the extension methods available on primitive types instead", since = "3.8.0") + @inline def shortWrapper(x: Short): runtime.RichShort = new runtime.RichShort(x) + @deprecated("use the extension methods available on primitive types instead", since = "3.8.0") + @inline def intWrapper(x: Int): runtime.RichInt = new runtime.RichInt(x) + @deprecated("use the extension methods available on primitive types instead", since = "3.8.0") + @inline def charWrapper(c: Char): runtime.RichChar = new runtime.RichChar(c) + @deprecated("use the extension methods available on primitive types instead", since = "3.8.0") + @inline def longWrapper(x: Long): runtime.RichLong = new runtime.RichLong(x) + @deprecated("use the extension methods available on primitive types instead", since = "3.8.0") + @inline def floatWrapper(x: Float): runtime.RichFloat = new runtime.RichFloat(x) + @deprecated("use the extension methods available on primitive types instead", since = "3.8.0") + @inline def doubleWrapper(x: Double): runtime.RichDouble = new runtime.RichDouble(x) + @deprecated("use the extension methods available on primitive types instead", since = "3.8.0") + @inline def booleanWrapper(x: Boolean): runtime.RichBoolean = new runtime.RichBoolean(x) /** @group conversions-array-to-wrapped-array */ implicit def genericWrapArray[T](xs: Array[T]): ArraySeq[T] = diff --git a/library/src/scala/Short.scala b/library/src/scala/Short.scala index 03b0929ea5ce..ac16fc1eef84 100644 --- a/library/src/scala/Short.scala +++ b/library/src/scala/Short.scala @@ -18,6 +18,8 @@ package scala import scala.language.`2.13` +import scala.collection.immutable.NumericRange + /** `Short`, a 16-bit signed integer (equivalent to Java's `short` primitive type) is a * subtype of [[scala.AnyVal]]. Instances of `Short` are not * represented by an object in the underlying runtime system. @@ -484,5 +486,88 @@ object Short extends AnyValCompanion { implicit def short2long(x: Short): Long = x.toLong implicit def short2float(x: Short): Float = x.toFloat implicit def short2double(x: Short): Double = x.toDouble -} + extension (self: Short) { + /** Returns `'''true'''` if this number has no decimal component. + * Always `'''true'''` for `Short`. + */ + @deprecated("isWhole on Short is always true", "2.12.15") + def isWhole: Boolean = true + + /** Returns `true` iff this is within the + * range of [[scala.Char]] MinValue and MaxValue; otherwise returns `false`. + */ + def isValidChar: Boolean = self >= 0 + + /** Returns `true` iff this is within the + * range of [[scala.Byte]] MinValue and MaxValue; otherwise returns `false`. + */ + def isValidByte: Boolean = self.toByte.toInt == self.toInt + + /** Returns `true` iff this is within the + * range of [[scala.Short]] MinValue and MaxValue; otherwise returns `false`. + */ + @deprecated("isValidShort on Short is always true", "3.8.0") + def isValidShort: Boolean = true + + /** Returns `true` iff this is within the + * range of [[scala.Int]] MinValue and MaxValue; otherwise returns `false`. + */ + @deprecated("isValidInt on Short is always true", "3.8.0") + def isValidInt: Boolean = true + + /** Returns the absolute value of `this`. */ + def abs: Short = java.lang.Math.abs(self.toInt).toShort + + /** Returns `this` if `this > that` or `that` otherwise. */ + def max(that: Short): Short = java.lang.Math.max(self.toInt, that.toInt).toShort + + /** Returns `this` if `this < that` or `that` otherwise. */ + def min(that: Short): Short = java.lang.Math.min(self.toInt, that.toInt).toShort + + /** Returns the sign of `this`. + * + * `0` if `this == 0`, `-1` if `this < 0` and `1` if `this > 0`. + */ + def sign: Short = java.lang.Integer.signum(self.toInt).toShort + + /** Returns the signum of `this`. */ + @deprecated("use `sign` method instead", since = "2.13.0") + def signum: Int = self.sign.toInt + + /** Compares `this` to `that` according to the standard total ordering. + * + * Returns: + * - a positive value if `this > that` + * - a negative value if `this < that` + * - `0` if `this == that` + */ + def compare(that: Short): Int = java.lang.Short.compare(self, that) + + /** A [[scala.collection.immutable.NumericRange]] from `this` up to but not including `end`. + * + * @param end The final bound of the range to make. + */ + def until(end: Short): NumericRange.Exclusive[Short] = NumericRange(self, end, 1) + + /** A [[scala.collection.immutable.NumericRange]] from `this` up to but not including `end`. + * + * @param end The final bound of the range to make. + * @param step The number to increase by for each step of the range. + */ + def until(end: Short, step: Short): NumericRange.Exclusive[Short] = NumericRange(self, end, step) + + /** A [[scala.collection.immutable.NumericRange]] from `this` up to and including `end`. + * + * @param end The final bound of the range to make. + */ + def to(end: Short): NumericRange.Inclusive[Short] = NumericRange.inclusive(self, end, 1) + + /** A [[scala.collection.immutable.NumericRange]] from `this` up to and including `end`. + * + * @param end The final bound of the range to make. + * @param step The number to increase by for each step of the range. + */ + def to(end: Short, step: Short): NumericRange.Inclusive[Short] = NumericRange.inclusive(self, end, step) + } +} diff --git a/library/src/scala/runtime/RichBoolean.scala b/library/src/scala/runtime/RichBoolean.scala index 9b7745f9859a..42131b60596d 100644 --- a/library/src/scala/runtime/RichBoolean.scala +++ b/library/src/scala/runtime/RichBoolean.scala @@ -15,6 +15,7 @@ package runtime import scala.language.`2.13` +@deprecated("use the extension methods available on primitive types instead", since = "3.8.0") final class RichBoolean(val self: Boolean) extends AnyVal with OrderedProxy[Boolean] { protected def ord: scala.math.Ordering.Boolean.type = scala.math.Ordering.Boolean } diff --git a/library/src/scala/runtime/RichByte.scala b/library/src/scala/runtime/RichByte.scala index 58b68b21b31b..251b665269de 100644 --- a/library/src/scala/runtime/RichByte.scala +++ b/library/src/scala/runtime/RichByte.scala @@ -15,6 +15,7 @@ package runtime import scala.language.`2.13` +@deprecated("use the extension methods available on primitive types instead", since = "3.8.0") final class RichByte(val self: Byte) extends AnyVal with ScalaWholeNumberProxy[Byte] { protected def num: scala.math.Numeric.ByteIsIntegral.type = scala.math.Numeric.ByteIsIntegral protected def ord: scala.math.Ordering.Byte.type = scala.math.Ordering.Byte diff --git a/library/src/scala/runtime/RichChar.scala b/library/src/scala/runtime/RichChar.scala index 8bdda656f987..257e6700a0ed 100644 --- a/library/src/scala/runtime/RichChar.scala +++ b/library/src/scala/runtime/RichChar.scala @@ -15,6 +15,7 @@ package runtime import scala.language.`2.13` +@deprecated("use the extension methods available on primitive types instead", since = "3.8.0") final class RichChar(val self: Char) extends AnyVal with IntegralProxy[Char] { protected def num: scala.math.Numeric.CharIsIntegral.type = scala.math.Numeric.CharIsIntegral protected def ord: scala.math.Ordering.Char.type = scala.math.Ordering.Char diff --git a/library/src/scala/runtime/RichDouble.scala b/library/src/scala/runtime/RichDouble.scala index a1b8bdd065fa..aaec3da6d463 100644 --- a/library/src/scala/runtime/RichDouble.scala +++ b/library/src/scala/runtime/RichDouble.scala @@ -15,6 +15,7 @@ package runtime import scala.language.`2.13` +@deprecated("use the extension methods available on primitive types instead", since = "3.8.0") final class RichDouble(val self: Double) extends AnyVal with FractionalProxy[Double] { protected def num: Fractional[Double] = scala.math.Numeric.DoubleIsFractional protected def ord: Ordering[Double] = scala.math.Ordering.Double.TotalOrdering diff --git a/library/src/scala/runtime/RichFloat.scala b/library/src/scala/runtime/RichFloat.scala index 78cabf5e7402..463980dd8778 100644 --- a/library/src/scala/runtime/RichFloat.scala +++ b/library/src/scala/runtime/RichFloat.scala @@ -15,6 +15,7 @@ package runtime import scala.language.`2.13` +@deprecated("use the extension methods available on primitive types instead", since = "3.8.0") final class RichFloat(val self: Float) extends AnyVal with FractionalProxy[Float] { protected def num: Fractional[Float] = scala.math.Numeric.FloatIsFractional protected def ord: Ordering[Float] = scala.math.Ordering.Float.TotalOrdering diff --git a/library/src/scala/runtime/RichInt.scala b/library/src/scala/runtime/RichInt.scala index 10d2d3b9ea0e..a7176cafd290 100644 --- a/library/src/scala/runtime/RichInt.scala +++ b/library/src/scala/runtime/RichInt.scala @@ -18,6 +18,7 @@ import scala.collection.immutable.Range // Note that this does not implement IntegralProxy[Int] so that it can return // the Int-specific Range class from until/to. +@deprecated("use the extension methods available on primitive types instead", since = "3.8.0") final class RichInt(val self: Int) extends AnyVal with ScalaNumberProxy[Int] with RangedProxy[Int] { protected def num: scala.math.Numeric.IntIsIntegral.type = scala.math.Numeric.IntIsIntegral protected def ord: scala.math.Ordering.Int.type = scala.math.Ordering.Int diff --git a/library/src/scala/runtime/RichLong.scala b/library/src/scala/runtime/RichLong.scala index 2dc7d6ffa2d4..f9ae309e389f 100644 --- a/library/src/scala/runtime/RichLong.scala +++ b/library/src/scala/runtime/RichLong.scala @@ -15,6 +15,7 @@ package runtime import scala.language.`2.13` +@deprecated("use the extension methods available on primitive types instead", since = "3.8.0") final class RichLong(val self: Long) extends AnyVal with IntegralProxy[Long] { protected def num: scala.math.Numeric.LongIsIntegral.type = scala.math.Numeric.LongIsIntegral protected def ord: scala.math.Ordering.Long.type = scala.math.Ordering.Long diff --git a/library/src/scala/runtime/RichShort.scala b/library/src/scala/runtime/RichShort.scala index 31f189380f94..3062fcc43c72 100644 --- a/library/src/scala/runtime/RichShort.scala +++ b/library/src/scala/runtime/RichShort.scala @@ -15,6 +15,7 @@ package runtime import scala.language.`2.13` +@deprecated("use the extension methods available on primitive types instead", since = "3.8.0") final class RichShort(val self: Short) extends AnyVal with ScalaWholeNumberProxy[Short] { protected def num: scala.math.Numeric.ShortIsIntegral.type = scala.math.Numeric.ShortIsIntegral protected def ord: scala.math.Ordering.Short.type = scala.math.Ordering.Short diff --git a/library/src/scala/runtime/ScalaNumberProxy.scala b/library/src/scala/runtime/ScalaNumberProxy.scala index cf70558469de..6a9845d1f54c 100644 --- a/library/src/scala/runtime/ScalaNumberProxy.scala +++ b/library/src/scala/runtime/ScalaNumberProxy.scala @@ -17,14 +17,12 @@ import scala.language.`2.13` import scala.collection.immutable import scala.math.ScalaNumericAnyConversions import immutable.NumericRange -import Proxy.Typed -import scala.annotation.nowarn /** Base classes for the Rich* wrappers of the primitive types. * As with all classes in scala.runtime.*, this is not a supported API. */ -@nowarn("cat=deprecation") -trait ScalaNumberProxy[T] extends Any with ScalaNumericAnyConversions with Typed[T] with OrderedProxy[T] { +@deprecated("use the extension methods available on primitive types instead", since = "3.8.0") +trait ScalaNumberProxy[T] extends Any with ScalaNumericAnyConversions with Proxy.Typed[T] with OrderedProxy[T] { protected implicit def num: Numeric[T] def doubleValue = num.toDouble(self) @@ -50,10 +48,14 @@ trait ScalaNumberProxy[T] extends Any with ScalaNumericAnyConversions with Typed /** Returns the signum of `'''this'''`. */ @deprecated("use `sign` method instead", since = "2.13.0") def signum: Int = num.signum(self) } + +@deprecated("use the extension methods available on primitive types instead", since = "3.8.0") trait ScalaWholeNumberProxy[T] extends Any with ScalaNumberProxy[T] { @deprecated("isWhole on an integer type is always true", "2.12.15") def isWhole = true } + +@deprecated("use the extension methods available on primitive types instead", since = "3.8.0") trait IntegralProxy[T] extends Any with ScalaWholeNumberProxy[T] with RangedProxy[T] { protected implicit def num: Integral[T] type ResultWithoutStep = NumericRange[T] @@ -63,21 +65,23 @@ trait IntegralProxy[T] extends Any with ScalaWholeNumberProxy[T] with RangedProx def to(end: T): NumericRange.Inclusive[T] = NumericRange.inclusive(self, end, num.one) def to(end: T, step: T): NumericRange.Inclusive[T] = NumericRange.inclusive(self, end, step) } + +@deprecated("use the extension methods available on primitive types instead", since = "3.8.0") trait FractionalProxy[T] extends Any with ScalaNumberProxy[T] { protected implicit def num: Fractional[T] def isWhole = false } -@nowarn("cat=deprecation") -trait OrderedProxy[T] extends Any with Ordered[T] with Typed[T] { +@deprecated("use the extension methods available on primitive types instead", since = "3.8.0") +trait OrderedProxy[T] extends Any with Ordered[T] with Proxy.Typed[T] { protected def ord: Ordering[T] def compare(y: T) = ord.compare(self, y) } -@nowarn("cat=deprecation") -trait RangedProxy[T] extends Any with Typed[T] { +@deprecated("use the extension methods available on primitive types instead", since = "3.8.0") +trait RangedProxy[T] extends Any with Proxy.Typed[T] { type ResultWithoutStep def until(end: T): ResultWithoutStep @@ -85,4 +89,3 @@ trait RangedProxy[T] extends Any with Typed[T] { def to(end: T): ResultWithoutStep def to(end: T, step: T): immutable.IndexedSeq[T] } -