- Scala Programming Projects
- Mikael Valot Nicolas Jorand
- 405字
- 2021-07-23 16:25:26
Refactoring the retirement calculator to use Option
Now that we know what Option can do for us, we are going to refactor one of the functions of the retirement calculator that we developed in Chapter 2, Developing a Retirement Calculator, to improve the handling of some edge-case scenarios. If you have not done it yet, please follow the instructions at the beginning of the Chapter 2, Developing a Retirement Calculator, to set up the project.
In RetCalc.scala, we are going to change the return type of nbMonthsSaving. In Chapter 2, Developing a Retirement Calculator, we returned Int.MaxValue if netIncome <= currentExpense to avoid looping infinitely. This was not very robust, as this infinite result could then be used in another computation, which would lead to bogus results. It would be better to return Option[Int] to indicate that the function might not be computable and let the caller decide what to do. We would return None if it was not computable or Some(returnValue) if it was computable.
The following code is the new implementation for nbMonthsSaving, with the changed portions highlighted in bold:
def nbOfMonthsSaving(params: RetCalcParams,
returns: Returns): Option[Int] = {
import params._
@tailrec
def loop(months: Int): Int = {
val (capitalAtRetirement, capitalAfterDeath) =
simulatePlan(returns, params, months)
if (capitalAfterDeath > 0.0)
months
else
loop(months + 1)
}
if (netIncome > currentExpenses)
Some(loop(0))
else
None
}
Now try to compile the project. This change breaks many parts of our project, but the Scala compiler is a terrific assistant. It will help us identify the portions of the code we need to change to make our code more robust.
The first error is in RetCalcSpec.scala, as shown in the following code:
Error:(65, 14) types Option[Int] and Int do not adhere to the type constraint selected for the === and !== operators; the missing implicit parameter is of type org.scalactic.CanEqual[Option[Int],Int]
actual should ===(expected)
This error means that the types in the actual should === (expected) expression do not match: actual is of the Option[Int]0 type, whereas expected is of the Int type. We need to change the assertion, as follows:
actual should ===(Some(expected))
You can apply the same fix for the second unit test. For the last unit test, we want to assert that None is returned instead of Int.MaxValue, as shown in the following code:
"not loop forever if I enter bad parameters" in {
val actual = RetCalc.nbOfMonthsSaving(params.copy(netIncome = 1000), FixedReturns(0.04))
actual should ===(None)
}
You can now compile and run the test. It should pass.
You are now able to model an optional value safely. However, sometimes it is not always obvious to know what None actually means. Why did this function return None? Was it because the arguments that were passed were wrong? Which argument was wrong? And what value would be correct? It would indeed be nice to have some explanation that comes along with the None in order to understand why there was no value. In the next section, we are going to use the Either type for this purpose.
- 物聯(lián)網(wǎng)安全(原書第2版)
- Building Django 2.0 Web Applications
- GPS/GNSS原理與應(yīng)用(第3版)
- 數(shù)字烏托邦
- 萬物互聯(lián):蜂窩物聯(lián)網(wǎng)組網(wǎng)技術(shù)詳解
- Web Application Development with R Using Shiny
- Hands-On Full Stack Development with Spring Boot 2 and React(Second Edition)
- 面向物聯(lián)網(wǎng)的嵌入式系統(tǒng)開發(fā):基于CC2530和STM32微處理器
- 網(wǎng)絡(luò)安全技術(shù)與解決方案(修訂版)
- NB-IoT物聯(lián)網(wǎng)技術(shù)解析與案例詳解
- Learning Swift(Second Edition)
- 智慧光網(wǎng)絡(luò):關(guān)鍵技術(shù)、應(yīng)用實(shí)踐和未來演進(jìn)
- Microsoft Power Platform Enterprise Architecture
- 組網(wǎng)技術(shù)與網(wǎng)絡(luò)管理
- 移動物聯(lián)網(wǎng):商業(yè)模式+案例分析+應(yīng)用實(shí)戰(zhàn)