using if instead of match on Option[X] - scala

I want to replace the below match with an if statement, preferably less verbose than this. I personally find if's to be easier to parse in the mind.
val obj = referencedCollection match{
case None => $set(nextColumn -> MongoDBObject("name" -> name))
case Some( collection) =>....}
Is there an equivalent if statement or some other method that produces the equivalent result?

You can replace the pattern match by a combination of map and getOrElse:
ox match {
case None => a
case Some(x) => f(x)
}
can be replaced by
ox.map(f).getOrElse(a)

You probably ought not indulge yourself in continuing to use if in conditions like this. It's not idiomatic, rarely is faster, is more verbose, requires intermediate variables so is more error-prone, etc..
Oh, and it's a bad idea to use anything with $ signs!
Here are some other patterns that you might use in addition to match:
val obj = referenceCollection.fold( $set(nextColumn -> MongoDBObject("name" -> name) ){
collection => ...
}
val obj = (for (collection <- referenceCollection) yield ...).getOrElse{
$set(nextColumn -> MongoDBObject("name" -> name)
}
val obj = referenceCollection.map{ collection => ... }.getOrElse{
$set(nextColumn -> MongoDBObject("name" -> name)
}
You can basically think of map as the if (x.isDefined) x.get... branch of the if and the getOrElse branch as the else $set... branch. It's not exactly the same, of course, as leaving off the else gives you an expression that doesn't return a value, while leaving off the getOrElse leaves you with an unpacked Option. But the thought-flow is very similar.
Anyway, fold is the most compact. Note that both of these have a bit of runtime overhead above a match or if statement.

There is huge number of options (pun intended):
if (referencedCollection != None) { ... } else { ... }
if (referencedCollection.isDefined) { ... } else { ... } // #Kigyo variant
if (referencedCollection.isEmpty) { /* None processing */ } else { ... }

You could do it like this:
val obj = if(referencedCollection.isDefined) { (work with referencedCollection.get) } else ...

Related

scala: updating string value in an option

I have an Option of a string. I want to update the contained value:
if(x.isEmpty) {
...another calculation
} else {
x.map(val => ...update val)
}
Is this an idiomatic way?
x.fold(another calculation)(v => ...update v)
e.g.
x.fold("no value")("Value is " + _)
Note that this extracts the value from the Option so if you want to have the result as an Option you need to wrap it in Some.
Note that if your inner computation gets too long or unreadable for a fold, there's always good old-fashioned pattern matching.
x match {
case None => {
// None case ...
}
case Some(y) => {
// Some case (y is the inside) ...
}
}
Like everything in Scala, this is an expression, so it can be assigned to a variable or used in another other expression you like.
Alternatively, using the lazy keyword:
// T is the type of the value
val valueOpt: Option[T] = ???
lazy val backupValue: T = ??? // Other calculation, but only evaluated if needed
val value: T = valueOpt.map( v => /*Update v*/ ).getOrElse( backupValue )
// do something with the value you want to manipulate

Idiomatic Scala for Options in place of if/else/else chain

I often find myself writing Scala of the form:
def foo = {
f1() match {
case Some(x1) => x1
case _ =>
f2() match {
case Some(x2) => x2
case _ =>
f3() match {
case Some(x3) => x3
case _ =>
f4()
}
}
}
}
This is the moral equivalent of Java's
Object foo() {
Object result = f1();
if (result != null) {
return result;
} else {
result = f2();
if (result != null) {
return result;
} else {
result = f3();
if (result != null) {
return result;
} else {
return f4();
}
}
}
}
and it seems ugly and unnecessarily verbose. I feel like there should be a readable way to do this in one line of Scala, but it's not clear to me what it is.
Note: I looked at Idiomatic Scala for Nested Options but it's a somewhat different case.
The idiomatic way to write nested pattern matching with options in Scala is by using the methods map, flatMap, orElse, and getOrElse.
You use map when you want to process the content of the option further and keep the optional behaviour:
So instead of this:
val opt: Option[Int] = ???
opt match {
case Some(x) => Some(x + 1)
case None => None
}
You would do this:
val opt: Option[Int] = ???
opt.map(_ + 1)
This chains much more naturally:
opt.map(_ + 1).map(_ * 3).map(_ - 2)
flatMap is verlly similar, but is used when your further operations return an option type as well.
In your particular example, orElse seems to be the most adapted solution. You can use orElse to return the option itself if not empty or else return the argument. Note that the argument is lazily evaluated so it is really equivalent to nested pattern matching/if-then-else.
def foo = {
f1().orElse(f2())
.orElse(f3())
.orElse(f4())
}
You can also combine these with getOrElse if you want to get rid of an Option. In your example you seem to return the final f4 as if it did not return an Option, so you would do the following:
def foo = {
f1().orElse(f2())
.orElse(f3())
.getOrElse(f4())
}
I know I am way late to the party, but feel that the orElse solution here is a bit clumsy. For me, the general functional idiom (not just scalaic) would be sth. along these lines (forgive me, I am not scala proficient):
def f1 = () => { println("f1 here"); null }
def f2 = () => { println("f2 here"); null }
def f3 = () => { println("f3 here"); 2 }
def f4 = () => { println("f4 here"); 3 }
def f5 = () => { println("f5 here"); 43 }
Stream(f1, f2, f3, f4, f5)
.map(f => f())
.dropWhile(_ == null)
.head
You use Stream as a lazy list, and basically, you say: Start invoking the functions and give me the first that does not evaluate to zero. Combining declarative approach and laziness gives you this generic piece of code, where the only thing you need to change when number of functions change, is the input list (stream) by adding just one more function element. That way, functions f1...fn become data, so you do not have to modify any existing code.
You could try:
f1() orElse f2() orElse Option(f3()) getOrElse f4()
Assuming that f1 and f2 returns options of the same type and f3 and f4 return a non-options of that same type
EDIT
It's not completely clear from your example if f3() returns an Option or not, so if it does then the code would be simplified to:
f1() orElse f2() orElse f3() getOrElse f4()
A slight tweak on cmbaxter's response that saves a few characters but is otherwise the same.
def foo = f1 orElse f2 orElse f3 getOrElse f4

Cleanest way in Scala to avoid nested ifs when transforming collections and checking for error conditions in each step

I have some code for validating ip addresses that looks like the following:
sealed abstract class Result
case object Valid extends Result
case class Malformatted(val invalid: Iterable[IpConfig]) extends Result
case class Duplicates(val dups: Iterable[Inet4Address]) extends Result
case class Unavailable(val taken: Iterable[Inet4Address]) extends Result
def result(ipConfigs: Iterable[IpConfig]): Result = {
val invalidIpConfigs: Iterable[IpConfig] =
ipConfigs.filterNot(ipConfig => {
(isValidIpv4(ipConfig.address)
&& isValidIpv4(ipConfig.gateway))
})
if (!invalidIpConfigs.isEmpty) {
Malformatted(invalidIpConfigs)
} else {
val ipv4it: Iterable[Inet4Address] = ipConfigs.map { ipConfig =>
InetAddress.getByName(ipConfig.address).asInstanceOf[Inet4Address]
}
val dups = ipv4it.groupBy(identity).filter(_._2.size != 1).keys
if (!dups.isEmpty) {
Duplicates(dups)
} else {
val ipAvailability: Map[Inet4Address, Boolean] =
ipv4it.map(ip => (ip, isIpAvailable(ip)))
val taken: Iterable[Inet4Address] = ipAvailability.filter(!_._2).keys
if (!taken.isEmpty) {
Unavailable(taken)
} else {
Valid
}
}
}
}
I don't like the nested ifs because it makes the code less readable. Is there a nice way to linearize this code? In java, I might use return statements, but this is discouraged in scala.
I personally advocate using a match everywhere you can, as it in my opinion usually makes code very readable
def result(ipConfigs: Iterable[IpConfig]): Result =
ipConfigs.filterNot(ipc => isValidIpv4(ipc.address) && isValidIpv4(ipc.gateway)) match {
case Nil =>
val ipv4it = ipConfigs.map { ipc =>
InetAddress.getByName(ipc.address).asInstanceOf[Inet4Address]
}
ipv4it.groupBy(identity).filter(_._2.size != 1).keys match {
case Nil =>
val taken = ipv4it.map(ip => (ip, isIpAvailable(ip))).filter(!_._2).keys
if (taken.nonEmpty) Unavailable(taken) else Valid
case dups => Duplicates(dups)
}
case invalid => Malformatted(invalid)
}
Note that I've chosen to match on the else part first, since you generally go from specific to generic in matches, since Nil is a subclass of Iterable I put that as the first case, eliminating the need for an i if i.nonEmpty in the other case, since it would be a given if it didn't match Nil
Also a thing to note here, all your vals don't need the type explicitly defined, it significantly declutters the code if you write something like
val ipAvailability: Map[Inet4Address, Boolean] =
ipv4it.map(ip => (ip, isIpAvailable(ip)))
as simply
val ipAvailability = ipv4it.map(ip => (ip, isIpAvailable(ip)))
I've also taken the liberty of removing many one-off variables I didn't find remotely necessary, as all they did was add more lines to the code
A thing to note here about using match over nested ifs, is that is that it's easier to add a new case than it is to add a new else if 99% of the time, thereby making it more modular, and modularity is always a good thing.
Alternatively, as suggested by Nathaniel Ford, you can break it up into several smaller methods, in which case the above code would look like so:
def result(ipConfigs: Iterable[IpConfig]): Result =
ipConfigs.filterNot(ipc => isValidIpv4(ipc.address) && isValidIpv4(ipc.gateway)) match {
case Nil => wellFormatted(ipConfigs)
case i => Malformatted(i)
}
def wellFormatted(ipConfigs: Iterable[IpConfig]): Result = {
val ipv4it = ipConfigs.map(ipc => InetAddress.getByName(ipc.address).asInstanceOf[Inet4Address])
ipv4it.groupBy(identity).filter(_._2.size != 1).keys match {
case Nil => noDuplicates(ipv4it)
case dups => Duplicates(dups)
}
}
def noDuplicates(ipv4it: Iterable[IpConfig]): Result =
ipv4it.map(ip => (ip, isIpAvailable(ip))).filter(!_._2).keys match {
case Nil => Valid
case taken => Unavailable(taken)
}
This has the benefit of splitting it up into smaller more manageable chunks, while keeping to the FP ideal of having functions that only do one thing, but do that one thing well, rather than having god-methods that do everything.
Which style you prefer, of course is up to you.
This has some time now but I will add my 2 cents. The proper way to handle this is with Either. You can create a method like:
def checkErrors[T](errorList: Iterable[T], onError: Result) : Either[Result, Unit] = if(errorList.isEmpty) Right() else Left(onError)
so you can use for comprehension syntax
val invalidIpConfigs = getFormatErrors(ipConfigs)
val result = for {
_ <- checkErrors(invalidIpConfigs, Malformatted(invalidIpConfigs))
dups = getDuplicates(ipConfigs)
_ <- checkErrors(dups, Duplicates(dups))
taken = getAvailability(ipConfigs)
_ <- checkErrors(taken, Unavailable(taken))
} yield Valid
If you don't want to return an Either use
result.fold(l => l, r => r)
In case of the check methods uses Futures (could be the case for getAvailability, for example), you can use cats library to be able of use it in a clean way: https://typelevel.org/cats/datatypes/eithert.html
I think it's pretty readable and I wouldn't try to improve it from there, except that !isEmpty equals to nonEmpty.

Consequent/nested pattern matches

When I send a variable through several pattern matches, what is the naming convention for doing so?
val somethingBetweenOriginalAndResult = original match {
case ...
case ...
}
val somethingElseBetweenOriginalAndResult = somethingBetweenOriginalAndResult match {
case ...
case ...
}
val result = somethingElseBetweenOriginalAndResult match {
case ...
case ...
}
In fact I only need original and result every val introduced in between smutches my namespace and requires me to excogitate a new variable name. How can I avoid this?
Use a block and short temporary variable names (just long enough to suggest to someone what you're trying to accomplish--if it's obvious, x and company will do fine):
val original = ...
val result = {
val x = original match { ... }
val y = x match { ... }
y match { ... }
}
You can even omit variable names entirely if you feel like it (though precedence is backwards so you need to add parens or something):
val result = {
((original match {
...
}) match {
...
}) match {
...
}
}
since the result of the previous match is the argument for the next one.
If you really don't care about somethingElseBetweenOriginalAndResult maybe you should try to avoid creating it at all. It really depends on the type of original and the cases you consider in your pattern matchings, but there is probably a way to achieve that with one pattern matching. Worst case scenario, why not use that :
val result = original match {
case ...
case ...
} match {
case ...
case ...
} match {
case ...
case ...
}
I don't like it really but at least you don't create an unnecessary value which you might accidentally refer to later on.

Scala Option - Getting rid of if (opt.isDefined) {}

My code is becoming littered with the following code pattern:
val opt = somethingReturningAnOpt
if (opt.isDefinedAt) {
val actualThingIWant = opt.get
}
Is there some way to simplify this? (it seems needlessly complex and a code smell). Ideally it would be something like:
if (Some(actualThingIWant) = somethingReturningAnOpt) {
doSomethingWith(actualThingIWant)
}
Is anything like that possible?
Maybe something like this:
somethingReturningAnOpt match {
case Some(actualThingIWant) => doSomethingWith(actualThingIWant)
case None =>
}
or as pst suggests:
somethingReturningAnOpt.foreach { actualThingIWant =>
doSomethingWith(actualThingIWant)
}
// or...
for (actualThingIWant <- somethingReturningAnOpt) {
doSomethingWith(actualThingIWant)
}
The canonical guide to Option wrangling is by Tony Morris.
Or:
somethingReturningAnOpt.map(doSomethingWith(_))
As in in:
val str = Some("foo")
str.map(_.toUpperCase)
... and use flatMap when the result of doSomethingWith is an Option itself.
val index = Option(Map("foo" -> "bar"))
index.flatMap(_.get("whatever")) // Returns None :-)
index.map(_.get("whatever")) // Returns Some(None) :-(
The following code cannot do something useful, since after the if, actualThingIWant is not always defined and as such this code will not compile, as long as you try to use actualThingIWant later.
val opt = somethingReturningAnOpt
if (opt.isDefinedAt) {
val actualThingIWant = opt.get
}
So, you have to provide a default value. This can be achieved with getOrElse:
val thingIWant = opt.getOrElse(myDefaultValue)
Or if you don't want to have actualThingIWant after the body of the if, which means you want to trigger some side-effects only if the option is defined, you can write:
opt.foreach{ thingIWant =>
println(thingIWant)
}
or a bit shorter
opt.foreach(println)