Skip to content

Commit

Permalink
Expanded the reach of value classes.
Browse files Browse the repository at this point in the history
Now extending AnyVal:

 - RichInt, RichDouble, etc.
 - ArrayOps.ofRef, ofBoolean, etc
 - StringAdd
 - StringFormat

The rest of it is the changes necessary to enable those.
  • Loading branch information
paulp committed Aug 29, 2012
1 parent e03a5b7 commit d3f879a
Show file tree
Hide file tree
Showing 25 changed files with 90 additions and 77 deletions.
21 changes: 13 additions & 8 deletions src/library/scala/LowPriorityImplicits.scala
Expand Up @@ -27,15 +27,20 @@ class LowPriorityImplicits {
* 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!
*/
implicit def byteWrapper(x: Byte) = new runtime.RichByte(x)
implicit def shortWrapper(x: Short) = new runtime.RichShort(x)
implicit def intWrapper(x: Int) = new runtime.RichInt(x)
implicit def charWrapper(c: Char) = new runtime.RichChar(c)
implicit def longWrapper(x: Long) = new runtime.RichLong(x)
implicit def floatWrapper(x: Float) = new runtime.RichFloat(x)
implicit def doubleWrapper(x: Double) = new runtime.RichDouble(x)
implicit def booleanWrapper(x: Boolean) = new runtime.RichBoolean(x)
@inline implicit def byteWrapper(x: Byte) = new runtime.RichByte(x)
@inline implicit def shortWrapper(x: Short) = new runtime.RichShort(x)
@inline implicit def intWrapper(x: Int) = new runtime.RichInt(x)
@inline implicit def charWrapper(c: Char) = new runtime.RichChar(c)
@inline implicit def longWrapper(x: Long) = new runtime.RichLong(x)
@inline implicit def floatWrapper(x: Float) = new runtime.RichFloat(x)
@inline implicit def doubleWrapper(x: Double) = new runtime.RichDouble(x)
@inline implicit def booleanWrapper(x: Boolean) = new runtime.RichBoolean(x)

// These eight implicits exist solely to exclude Null from the domain of
// the boxed types, so that e.g. "var x: Int = null" is a compile time
Expand Down
2 changes: 1 addition & 1 deletion src/library/scala/collection/CustomParallelizable.scala
Expand Up @@ -10,7 +10,7 @@ package scala.collection

import parallel.Combiner

trait CustomParallelizable[+A, +ParRepr <: Parallel] extends Parallelizable[A, ParRepr] {
trait CustomParallelizable[+A, +ParRepr <: Parallel] extends Any with Parallelizable[A, ParRepr] {
override def par: ParRepr
override protected[this] def parCombiner: Combiner[A, ParRepr] = throw new UnsupportedOperationException("")
}
Expand Down
2 changes: 1 addition & 1 deletion src/library/scala/collection/mutable/ArrayLike.scala
Expand Up @@ -22,7 +22,7 @@ import generic._
* @version 2.8
* @since 2.8
*/
trait ArrayLike[A, +Repr] extends IndexedSeqOptimized[A, Repr] { self =>
trait ArrayLike[A, +Repr] extends Any with IndexedSeqOptimized[A, Repr] { self =>

/** Creates a possible nested `IndexedSeq` which consists of all the elements
* of this array. If the elements are arrays themselves, the `deep` transformation
Expand Down
28 changes: 12 additions & 16 deletions src/library/scala/collection/mutable/ArrayOps.scala
Expand Up @@ -6,18 +6,14 @@
** |/ **
\* */



package scala.collection
package mutable
import compat.Platform.arraycopy

import compat.Platform.arraycopy
import scala.reflect.ClassTag
import scala.runtime.ScalaRunTime._

import parallel.mutable.ParArray


/** This class serves as a wrapper for `Array`s with all the operations found in
* indexed sequences. Where needed, instances of arrays are implicitly converted
* into this class.
Expand All @@ -36,7 +32,7 @@ import parallel.mutable.ParArray
* @define mayNotTerminateInf
* @define willNotTerminateInf
*/
abstract class ArrayOps[T] extends ArrayLike[T, Array[T]] with CustomParallelizable[T, ParArray[T]] {
trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParallelizable[T, ParArray[T]] {

private def elementClass: Class[_] =
arrayElementClass(repr.getClass)
Expand Down Expand Up @@ -105,7 +101,7 @@ abstract class ArrayOps[T] extends ArrayLike[T, Array[T]] with CustomParalleliza
object ArrayOps {

/** A class of `ArrayOps` for arrays containing reference types. */
class ofRef[T <: AnyRef](override val repr: Array[T]) extends ArrayOps[T] with ArrayLike[T, Array[T]] {
final class ofRef[T <: AnyRef](override val repr: Array[T]) extends AnyVal with ArrayOps[T] with ArrayLike[T, Array[T]] {

override protected[this] def thisCollection: WrappedArray[T] = new WrappedArray.ofRef[T](repr)
override protected[this] def toCollection(repr: Array[T]): WrappedArray[T] = new WrappedArray.ofRef[T](repr)
Expand All @@ -117,7 +113,7 @@ object ArrayOps {
}

/** A class of `ArrayOps` for arrays containing `byte`s. */
class ofByte(override val repr: Array[Byte]) extends ArrayOps[Byte] with ArrayLike[Byte, Array[Byte]] {
final class ofByte(override val repr: Array[Byte]) extends AnyVal with ArrayOps[Byte] with ArrayLike[Byte, Array[Byte]] {

override protected[this] def thisCollection: WrappedArray[Byte] = new WrappedArray.ofByte(repr)
override protected[this] def toCollection(repr: Array[Byte]): WrappedArray[Byte] = new WrappedArray.ofByte(repr)
Expand All @@ -129,7 +125,7 @@ object ArrayOps {
}

/** A class of `ArrayOps` for arrays containing `short`s. */
class ofShort(override val repr: Array[Short]) extends ArrayOps[Short] with ArrayLike[Short, Array[Short]] {
final class ofShort(override val repr: Array[Short]) extends AnyVal with ArrayOps[Short] with ArrayLike[Short, Array[Short]] {

override protected[this] def thisCollection: WrappedArray[Short] = new WrappedArray.ofShort(repr)
override protected[this] def toCollection(repr: Array[Short]): WrappedArray[Short] = new WrappedArray.ofShort(repr)
Expand All @@ -141,7 +137,7 @@ object ArrayOps {
}

/** A class of `ArrayOps` for arrays containing `char`s. */
class ofChar(override val repr: Array[Char]) extends ArrayOps[Char] with ArrayLike[Char, Array[Char]] {
final class ofChar(override val repr: Array[Char]) extends AnyVal with ArrayOps[Char] with ArrayLike[Char, Array[Char]] {

override protected[this] def thisCollection: WrappedArray[Char] = new WrappedArray.ofChar(repr)
override protected[this] def toCollection(repr: Array[Char]): WrappedArray[Char] = new WrappedArray.ofChar(repr)
Expand All @@ -153,7 +149,7 @@ object ArrayOps {
}

/** A class of `ArrayOps` for arrays containing `int`s. */
class ofInt(override val repr: Array[Int]) extends ArrayOps[Int] with ArrayLike[Int, Array[Int]] {
final class ofInt(override val repr: Array[Int]) extends AnyVal with ArrayOps[Int] with ArrayLike[Int, Array[Int]] {

override protected[this] def thisCollection: WrappedArray[Int] = new WrappedArray.ofInt(repr)
override protected[this] def toCollection(repr: Array[Int]): WrappedArray[Int] = new WrappedArray.ofInt(repr)
Expand All @@ -165,7 +161,7 @@ object ArrayOps {
}

/** A class of `ArrayOps` for arrays containing `long`s. */
class ofLong(override val repr: Array[Long]) extends ArrayOps[Long] with ArrayLike[Long, Array[Long]] {
final class ofLong(override val repr: Array[Long]) extends AnyVal with ArrayOps[Long] with ArrayLike[Long, Array[Long]] {

override protected[this] def thisCollection: WrappedArray[Long] = new WrappedArray.ofLong(repr)
override protected[this] def toCollection(repr: Array[Long]): WrappedArray[Long] = new WrappedArray.ofLong(repr)
Expand All @@ -177,7 +173,7 @@ object ArrayOps {
}

/** A class of `ArrayOps` for arrays containing `float`s. */
class ofFloat(override val repr: Array[Float]) extends ArrayOps[Float] with ArrayLike[Float, Array[Float]] {
final class ofFloat(override val repr: Array[Float]) extends AnyVal with ArrayOps[Float] with ArrayLike[Float, Array[Float]] {

override protected[this] def thisCollection: WrappedArray[Float] = new WrappedArray.ofFloat(repr)
override protected[this] def toCollection(repr: Array[Float]): WrappedArray[Float] = new WrappedArray.ofFloat(repr)
Expand All @@ -189,7 +185,7 @@ object ArrayOps {
}

/** A class of `ArrayOps` for arrays containing `double`s. */
class ofDouble(override val repr: Array[Double]) extends ArrayOps[Double] with ArrayLike[Double, Array[Double]] {
final class ofDouble(override val repr: Array[Double]) extends AnyVal with ArrayOps[Double] with ArrayLike[Double, Array[Double]] {

override protected[this] def thisCollection: WrappedArray[Double] = new WrappedArray.ofDouble(repr)
override protected[this] def toCollection(repr: Array[Double]): WrappedArray[Double] = new WrappedArray.ofDouble(repr)
Expand All @@ -201,7 +197,7 @@ object ArrayOps {
}

/** A class of `ArrayOps` for arrays containing `boolean`s. */
class ofBoolean(override val repr: Array[Boolean]) extends ArrayOps[Boolean] with ArrayLike[Boolean, Array[Boolean]] {
final class ofBoolean(override val repr: Array[Boolean]) extends AnyVal with ArrayOps[Boolean] with ArrayLike[Boolean, Array[Boolean]] {

override protected[this] def thisCollection: WrappedArray[Boolean] = new WrappedArray.ofBoolean(repr)
override protected[this] def toCollection(repr: Array[Boolean]): WrappedArray[Boolean] = new WrappedArray.ofBoolean(repr)
Expand All @@ -213,7 +209,7 @@ object ArrayOps {
}

/** A class of `ArrayOps` for arrays of `Unit` types. */
class ofUnit(override val repr: Array[Unit]) extends ArrayOps[Unit] with ArrayLike[Unit, Array[Unit]] {
final class ofUnit(override val repr: Array[Unit]) extends AnyVal with ArrayOps[Unit] with ArrayLike[Unit, Array[Unit]] {

override protected[this] def thisCollection: WrappedArray[Unit] = new WrappedArray.ofUnit(repr)
override protected[this] def toCollection(repr: Array[Unit]): WrappedArray[Unit] = new WrappedArray.ofUnit(repr)
Expand Down
2 changes: 1 addition & 1 deletion src/library/scala/collection/mutable/IndexedSeqLike.scala
Expand Up @@ -36,7 +36,7 @@ import generic._
* @define willNotTerminateInf
* @define mayNotTerminateInf
*/
trait IndexedSeqLike[A, +Repr] extends scala.collection.IndexedSeqLike[A, Repr] { self =>
trait IndexedSeqLike[A, +Repr] extends Any with scala.collection.IndexedSeqLike[A, Repr] { self =>

override protected[this] def thisCollection: IndexedSeq[A] = this.asInstanceOf[IndexedSeq[A]]
override protected[this] def toCollection(repr: Repr): IndexedSeq[A] = repr.asInstanceOf[IndexedSeq[A]]
Expand Down
Expand Up @@ -17,4 +17,4 @@ import generic._
*
* @since 2.8
*/
trait IndexedSeqOptimized[A, +Repr] extends IndexedSeqLike[A, Repr] with scala.collection.IndexedSeqOptimized[A, Repr]
trait IndexedSeqOptimized[A, +Repr] extends Any with IndexedSeqLike[A, Repr] with scala.collection.IndexedSeqOptimized[A, Repr]
2 changes: 1 addition & 1 deletion src/library/scala/math/BigDecimal.scala
Expand Up @@ -211,7 +211,7 @@ extends ScalaNumber with ScalaNumericConversions with Serializable {
catch { case _: ArithmeticException => false }
}

protected[math] def isWhole = (this remainder 1) == BigDecimal(0)
def isWhole() = (this remainder 1) == BigDecimal(0)
def underlying = bigDecimal

/** Compares this BigDecimal with the specified BigDecimal for equality.
Expand Down
4 changes: 2 additions & 2 deletions src/library/scala/math/BigInt.scala
Expand Up @@ -162,15 +162,15 @@ class BigInt(val bigInteger: BigInteger) extends ScalaNumber with ScalaNumericCo
}
/** Some implementations of java.math.BigInteger allow huge values with bit length greater than Int.MaxValue .
* The BigInteger.bitLength method returns truncated bit length in this case .
* This method tests if result of bitLength is valid.
* This method tests if result of bitLength is valid.
* This method will become unnecessary if BigInt constructors reject huge BigIntegers.
*/
private def bitLengthOverflow = {
val shifted = bigInteger.shiftRight(Int.MaxValue)
(shifted.signum != 0) && !(shifted equals BigInt.minusOne)
}

protected[math] def isWhole = true
def isWhole() = true
def underlying = bigInteger

/** Compares this BigInt with the specified BigInt for equality.
Expand Down
12 changes: 11 additions & 1 deletion src/library/scala/math/ScalaNumericConversions.scala
Expand Up @@ -13,7 +13,17 @@ import java.{ lang => jl }
/** Conversions which present a consistent conversion interface
* across all the numeric types.
*/
trait ScalaNumericConversions extends ScalaNumber {
trait ScalaNumericConversions extends Any {
def isWhole(): Boolean
def underlying(): Any

def byteValue(): Byte = intValue().toByte
def shortValue(): Short = intValue().toShort
def intValue(): Int
def longValue(): Long
def floatValue(): Float
def doubleValue(): Double

/** Returns the value of this as a [[scala.Char]]. This may involve
* rounding or truncation.
*/
Expand Down
4 changes: 2 additions & 2 deletions src/library/scala/runtime/RichBoolean.scala
Expand Up @@ -8,6 +8,6 @@

package scala.runtime

final class RichBoolean(val self: Boolean) extends OrderedProxy[Boolean] {
protected val ord = math.Ordering[Boolean]
final class RichBoolean(val self: Boolean) extends AnyVal with OrderedProxy[Boolean] {
protected def ord = scala.math.Ordering.Boolean
}
5 changes: 4 additions & 1 deletion src/library/scala/runtime/RichByte.scala
Expand Up @@ -8,4 +8,7 @@

package scala.runtime

final class RichByte(val self: Byte) extends ScalaWholeNumberProxy[Byte] { }
final class RichByte(val self: Byte) extends AnyVal with ScalaWholeNumberProxy[Byte] {
protected def num = scala.math.Numeric.ByteIsIntegral
protected def ord = scala.math.Ordering.Byte
}
5 changes: 4 additions & 1 deletion src/library/scala/runtime/RichChar.scala
Expand Up @@ -10,7 +10,10 @@ package scala.runtime

import java.lang.Character

final class RichChar(val self: Char) extends IntegralProxy[Char] {
final class RichChar(val self: Char) extends AnyVal with IntegralProxy[Char] {
protected def num = scala.math.Numeric.CharIsIntegral
protected def ord = scala.math.Ordering.Char

def asDigit: Int = Character.digit(self, Character.MAX_RADIX)

def isControl: Boolean = Character.isISOControl(self)
Expand Down
6 changes: 4 additions & 2 deletions src/library/scala/runtime/RichDouble.scala
Expand Up @@ -8,8 +8,10 @@

package scala.runtime

final class RichDouble(val self: Double) extends FractionalProxy[Double] {
protected val integralNum = Numeric.DoubleAsIfIntegral
final class RichDouble(val self: Double) extends AnyVal with FractionalProxy[Double] {
protected def num = scala.math.Numeric.DoubleIsFractional
protected def ord = scala.math.Ordering.Double
protected def integralNum = scala.math.Numeric.DoubleAsIfIntegral

def round: Long = math.round(self)
def ceil: Double = math.ceil(self)
Expand Down
6 changes: 4 additions & 2 deletions src/library/scala/runtime/RichFloat.scala
Expand Up @@ -8,8 +8,10 @@

package scala.runtime

final class RichFloat(val self: Float) extends FractionalProxy[Float] {
protected val integralNum = Numeric.FloatAsIfIntegral
final class RichFloat(val self: Float) extends AnyVal with FractionalProxy[Float] {
protected def num = scala.math.Numeric.FloatIsFractional
protected def ord = scala.math.Ordering.Float
protected def integralNum = scala.math.Numeric.FloatAsIfIntegral

def round: Int = math.round(self)
def ceil: Float = math.ceil(self).toFloat
Expand Down
4 changes: 3 additions & 1 deletion src/library/scala/runtime/RichInt.scala
Expand Up @@ -12,7 +12,9 @@ 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.
final class RichInt(val self: Int) extends ScalaNumberProxy[Int] with RangedProxy[Int] {
final class RichInt(val self: Int) extends AnyVal with ScalaNumberProxy[Int] with RangedProxy[Int] {
protected def num = scala.math.Numeric.IntIsIntegral
protected def ord = scala.math.Ordering.Int
type ResultWithoutStep = Range

/**
Expand Down
5 changes: 4 additions & 1 deletion src/library/scala/runtime/RichLong.scala
Expand Up @@ -8,7 +8,10 @@

package scala.runtime

final class RichLong(val self: Long) extends IntegralProxy[Long] {
final class RichLong(val self: Long) extends AnyVal with IntegralProxy[Long] {
protected def num = scala.math.Numeric.LongIsIntegral
protected def ord = scala.math.Ordering.Long

def toBinaryString: String = java.lang.Long.toBinaryString(self)
def toHexString: String = java.lang.Long.toHexString(self)
def toOctalString: String = java.lang.Long.toOctalString(self)
Expand Down
5 changes: 4 additions & 1 deletion src/library/scala/runtime/RichShort.scala
Expand Up @@ -8,4 +8,7 @@

package scala.runtime

final class RichShort(val self: Short) extends ScalaWholeNumberProxy[Short] { }
final class RichShort(val self: Short) extends AnyVal with ScalaWholeNumberProxy[Short] {
protected def num = scala.math.Numeric.ShortIsIntegral
protected def ord = scala.math.Ordering.Short
}
19 changes: 9 additions & 10 deletions src/library/scala/runtime/ScalaNumberProxy.scala
Expand Up @@ -20,9 +20,8 @@ import Proxy.Typed
* @version 2.9
* @since 2.9
*/
abstract class ScalaNumberProxy[T: Numeric] extends ScalaNumericConversions with Typed[T] with OrderedProxy[T] {
private val num = implicitly[Numeric[T]]
protected val ord: Ordering[T] = num
trait ScalaNumberProxy[T] extends Any with ScalaNumericConversions with Typed[T] with OrderedProxy[T] {
protected implicit def num: Numeric[T]

def underlying() = self.asInstanceOf[AnyRef]
def doubleValue() = num.toDouble(self)
Expand All @@ -35,29 +34,29 @@ abstract class ScalaNumberProxy[T: Numeric] extends ScalaNumericConversions with
def abs = num.abs(self)
def signum = num.signum(self)
}
abstract class ScalaWholeNumberProxy[T: Numeric] extends ScalaNumberProxy[T] {
trait ScalaWholeNumberProxy[T] extends Any with ScalaNumberProxy[T] {
def isWhole() = true
}
abstract class IntegralProxy[T : Integral] extends ScalaWholeNumberProxy[T] with RangedProxy[T] {
private lazy val num = implicitly[Integral[T]]
trait IntegralProxy[T] extends Any with ScalaWholeNumberProxy[T] with RangedProxy[T] {
protected implicit def num: Integral[T]
type ResultWithoutStep = NumericRange[T]

def until(end: T): NumericRange.Exclusive[T] = NumericRange(self, end, num.one)
def until(end: T, step: T): NumericRange.Exclusive[T] = NumericRange(self, end, step)
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)
}
abstract class FractionalProxy[T : Fractional] extends ScalaNumberProxy[T] with RangedProxy[T] {
def isWhole() = false
trait FractionalProxy[T] extends Any with ScalaNumberProxy[T] with RangedProxy[T] {
protected implicit def num: Fractional[T]
protected implicit def integralNum: Integral[T]

/** In order to supply predictable ranges, we require an Integral[T] which provides
* us with discrete operations on the (otherwise fractional) T. See Numeric.DoubleAsIfIntegral
* for an example.
*/
protected implicit def integralNum: Integral[T]
private lazy val num = implicitly[Fractional[T]]
type ResultWithoutStep = Range.Partial[T, NumericRange[T]]

def isWhole() = false
def until(end: T): ResultWithoutStep = new Range.Partial(NumericRange(self, end, _))
def until(end: T, step: T): NumericRange.Exclusive[T] = NumericRange(self, end, step)
def to(end: T): ResultWithoutStep = new Range.Partial(NumericRange.inclusive(self, end, _))
Expand Down
5 changes: 1 addition & 4 deletions src/library/scala/runtime/StringAdd.scala
Expand Up @@ -9,14 +9,11 @@
package scala.runtime

/** A wrapper class that adds string concatenation `+` to any value */
final class StringAdd(val self: Any) {

final class StringAdd(val self: Any) extends AnyVal {
// Note: The implicit conversion from Any to StringAdd is one of two
// implicit conversions from Any to AnyRef in Predef. It is important to have at least
// two such conversions, so that silent conversions from value types to AnyRef
// are avoided. If StringFormat should become a value class, another
// implicit conversion from Any to AnyRef has to be introduced in Predef

def +(other: String) = String.valueOf(self) + other

}
4 changes: 1 addition & 3 deletions src/library/scala/runtime/StringFormat.scala
Expand Up @@ -10,8 +10,7 @@ package scala.runtime

/** A wrapper class that adds a `formatted` operation to any value
*/
final class StringFormat(val self: Any) {

final class StringFormat(val self: Any) extends AnyVal {
// Note: The implicit conversion from Any to StringFormat is one of two
// implicit conversions from Any to AnyRef in Predef. It is important to have at least
// two such conversions, so that silent conversions from value types to AnyRef
Expand All @@ -23,5 +22,4 @@ final class StringFormat(val self: Any) {
* (@see java.lang.String.format).
*/
@inline def formatted(fmtstr: String): String = fmtstr format self

}

0 comments on commit d3f879a

Please sign in to comment.