Why is foreach better than get for Scala Options?
Why using foreach
, map
, flatMap
etc. are considered better than using get
for Scala Options? If I useisEmpty
I can call get
safely.
Solution 1:
Well, it kind of comes back to "tell, don't ask". Consider these two lines:
if (opt.isDefined) println(opt.get)
// versus
opt foreach println
In the first case, you are looking inside opt
and then reacting depending on what you see. In the second case you are just telling opt
what you want done, and let it deal with it.
The first case knows too much about Option
, replicates logic internal to it, is fragile and prone to errors (it can result in run-time errors, instead of compile-time errors, if written incorrectly).
Add to that, it is not composable. If you have three options, a single for comprehension takes care of them:
for {
op1 <- opt1
op2 <- opt2
op3 <- opt3
} println(op1+op2+op3)
With if
, things start to get messy fast.
Solution 2:
One nice reason to use foreach
is parsing something with nested options. If you have something like
val nestedOption = Some(Some(Some(1)))
for {
opt1 <- nestedOption
opt2 <- opt1
opt3 <- opt2
} println(opt3)
The console prints 1
. If you extend this to a case where you have a class that optionally stores a reference to something, which in turn stores another reference, for comprehensions allow you to avoid a giant "pyramid" of None/Some checking.
Solution 3:
There are already excellent answers to the actual question, but for more Option
-foo you should definitely check out Tony Morris' Option Cheat Sheet.
Solution 4:
The reason it's more useful to apply things like map
, foreach
, and flatMap
directly to the Option
instead of using get
and then performing the function is that it works on either Some
or None
and you don't have to do special checks to make sure the value is there.
val x: Option[Int] = foo()
val y = x.map(_+1) // works fine for None
val z = x.get + 1 // doesn't work if x is None
The result for y
here is an Option[Int]
, which is desirable since if x
is optional, then y
might be undetermined as well. Since get
doesn't work on None
, you'd have to do a bunch of extra work to make sure you didn't get any errors; extra work that is done for you by map
.