I’m learning scala for a new project, aiming for immutability and functional style wherever possible.
One of the objects I’m creating takes a number of inputs in its constructor, then repeatedly applies a large number of calculations to generate the relevant outputs, which are stored as fields on the object.
While the calculations are performed and their results added to a mutable ListBuffer internally, everything else about the object is immutable – once created you can’t change any of the input values and running the calculations again would obviously produce the same result.
However, it doesn’t seem right to me to have so many calculations in the constructor. The only way around it I can see is to have the calculated values be vars and provide a run method which performs the calculations – but then this method could be called multiple times, which would be pointless.
Is it actually OK style to do a lot in a scala constructor? There’s no calls to the DB for example, just internal calculations. Or is there some pattern for this?
Here’s the basic idea in very very simple form:
class Foo(val x:Int, val y:Int, calculations:List[Calculation]) {
val xHistory = new collection.mutable.ListBuffer[Int]()
val yHistory = new collection.mutable.ListBuffer[Int]()
calculations.map { calc => calc.perform(this) }.foreach { result =>
xHistory += result.x
yHistory += result.y
}
}
Basically I want the inputs wrapped in a handy instance of a Foo object so I can pass it to the various calculation strategies (each of which may need a different combination of inputs).
Work inside the constructor
Usually I do expensive stuff inside the constructor. But note that the comments mention that constructor code might be less optimized by (insert Java implementation here for which this is correct). Also read the next paragraph if you have a multi-threaded application.
Delayed Init
I don’t know anything that might be wrong with doing much work inside a constructor.As noted inside the comments, there may be problems with code running inside the constructor concerning concurrency. Therefor the
DelayedInittrait has been introduced in Scala 2.8.0. Problems with of this kind occur for example when working with Swing GUI elements.Lazy Constructs
To delay the computations in a different way, you can use the following methods, which also solve the concurrency issue:
lazy valmembers, which will get computed once they are first requested.Stream. This is like aListthat computes the next element only on demand. Thus at some point in time, only the initial part of theStreamthat has already been accessed has been computed.Indication to use
lazyAnother consideration you might want to do is whether the computed values will get used at all. If they might not be needed, then using the lazy methods I described is the way to go. On the other hand, if you definately access these expensive memebers, in my opinion there is nothing wrong with doing the computations inside a constructor and using lazy members might add unescessary computational overhead.
Note regarding OP example
It’s not ok to do dangerous things inside the constructor; like letting references to the partially constructed object escape the constructor (via a
this-reference). The example inside the OP does this withcalc.perform(this). This “potential bug” cannot be fixed with the following suggestions.