performance - Is it possible to have an Array which evaluates its elements lazily? -
consider bigint class, should cache common values in smallvalues
:
object bigint { lazy val smallvalues = array(zero, one, two) lazy val 0 = new bigint(0, array[long]()) lazy val 1 = new bigint(1, array[long](1)) lazy val 2 = new bigint(1, array[long](2)) private lazy val cachesize = smallvalues.length def apply(num: long): bigint = { // number cached? if (0 <= num && num < cachesize) smallvalues(num.toint) // figure out sign , make number positive after 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 accessing 1 element of array forces evaluation of elements:
scala> bigint.smallvalues(0) constructing bigint constructing bigint constructing bigint res0: bigint = bigint@2c176570
how solve that?
edit: looking @ proposed solutions wonder if wouldn't more efficient allocate them without further complication. think?
editing answer because thought toy example of want , real objects expensive build laziness bought something. if question shows more real code laziness makes no sense. lazy object bigger , more expensive create strict ones are. still, i'm keeping following code because show how create lazy wrapper , "work" (in sense it's functionally correct) if doesn't "work" in sense of being idea 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 = { // number cached? if (0 <= num && num < cachesize) smallvalues(num.toint)! // figure out sign , make number positive after 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
Comments
Post a Comment