Refactoring simulatePlan

Since simulatePlan calls futureCapital, we need to change its implementation to take into account the new return type, as shown in the following code:

def simulatePlan(returns: Returns, params: RetCalcParams, nbOfMonthsSavings: Int,
monthOffset: Int = 0): Either[RetCalcError, (Double,
Double)]
= {
import params._

for {
capitalAtRetirement <- futureCapital(
returns = OffsetReturns(returns, monthOffset),
nbOfMonths = nbOfMonthsSavings, netIncome = netIncome,
currentExpenses = currentExpenses,
initialCapital = initialCapital)

capitalAfterDeath <- futureCapital(
returns = OffsetReturns(returns, monthOffset +
nbOfMonthsSavings),
nbOfMonths = nbOfMonthsInRetirement,
netIncome = 0, currentExpenses = currentExpenses,
initialCapital = capitalAtRetirement)
} yield (capitalAtRetirement, capitalAfterDeath)
}

We moved the two calls to futureCapital inside a for comprehension. This way, if any of these calls return an error, simulatePlan will return it. If both calls succeed, simulatePlan will return the two double values in a tuple.

Compile the project. Now we need to fix a compilation error in nbOfMonthsSaving, which uses simulatePlan. The following code is the fixed version:

def nbOfMonthsSaving(params: RetCalcParams, returns: Returns): Either[RetCalcError, Int] = {
import params._
@tailrec
def loop(months: Int): Either[RetCalcError, Int] = {
simulatePlan(returns, params, months) match {
case Right((capitalAtRetirement, capitalAfterDeath)) =>
if (capitalAfterDeath > 0.0)
Right(months)
else
loop(months + 1)

case Left(err) => Left(err)
}
}

if (netIncome > currentExpenses)
loop(0)
else
Left(MoreExpensesThanIncome(netIncome, currentExpenses))
}

We had to change our recursive loop function to return Either[RetCalcError, Int]. The loop will stop as soon as we get an error or if (capitalAfterDeath > 0.0). You might wonder why we did not use flatMap instead of using pattern matching. It would indeed have been more concise, but the loop function would not be tail recursive anymore, because the recursive call to loop would be inside an anonymous function. As an exercise, I encourage you to try changing the code so that it uses flatMap and observe the tail recursion compilation error.

Compile the project. The last compilation error in the production code is in SimulatePlanApp.scala.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset