Consider this BigInt class, which should cache some common values in smallValues
:
object BigInt {
lazy val smallValues = Array(Zero, One, Two)
lazy val Zero = new BigInt(0, Array[Long]())
lazy val One = new BigInt(1, Array[Long](1))
lazy val Two = new BigInt(1, Array[Long](2))
private lazy val cacheSize = smallValues.length
def apply(num: Long): BigInt = {
// Is the number cached?
if (0 <= num && num < cacheSize) smallValues(num.toInt)
// Figure out the sign and make the number positive after that
else {
val (sign, value) = if (num < 0) (-1, num * -1) else (1, num)
new BigInt(sign, Array(value))
}
}
}
class BigInt private(val sign: Int, val num: Array[Long]) extends Ordered[BigInt] {
println("Constructing BigInt")
...
}
The problem here is that accessing one element of the array forces the evaluation of all elements:
scala> BigInt.smallValues(0)
Constructing BigInt
Constructing BigInt
Constructing BigInt
res0: BigInt = BigInt@2c176570
How could I solve that?
Edit: Looking at the proposed solutions I really wonder if it wouldn't be more efficient to just allocate them without further complication. What do you think?
Editing my answer because I thought this was a toy example of what you want to do and that your real objects were so expensive to build that laziness bought you something. If the question shows something more like real code then laziness makes no sense. The lazy object are bigger and more expensive to create than the strict ones are. Still, I'm keeping the following code because it does show how create a lazy wrapper and that it does "work" (in the sense that it's functionally correct) even if it doesn't "work" in the sense of being a good idea for your use case.
class Lazy[T] (expr : => T) {lazy val ! = expr}
object Lazy{def apply[T](expr : => T) = new Lazy({expr})}
class BigInt (val sign: Int, val num: Array[Long]) {
println("Constructing BigInt")
}
object BigInt {
val smallValues = Array(
Lazy(new BigInt(0, Array[Long]())),
Lazy(new BigInt(1, Array[Long](1))),
Lazy(new BigInt(1, Array[Long](2)))
)
private val cacheSize = smallValues.length.toLong
def apply(num: Long): BigInt = {
// Is the number cached?
if (0 <= num && num < cacheSize) smallValues(num.toInt)!
// Figure out the sign and make the number positive after that
else {
val (sign, value) = if (num < 0) (-1, num * -1) else (1, num)
new BigInt(sign, Array(value))
}
}
}
scala> BigInt(1)
Constructing BigInt
res0: BigInt = BigInt@c0dd841
scala> BigInt(1)
res1: BigInt = BigInt@c0dd841
scala> BigInt(2)
Constructing BigInt
res2: BigInt = BigInt@4a6a00ca
scala> BigInt(2)
res3: BigInt = BigInt@4a6a00ca
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With