The Scala Option has really grown on me. I can't believe I didn't embrace it earlier. There are several great posts, but one of the best I've found is scala.Option Cheat Sheet from Tony Morris' blog.
Yesterday, I was trying to unload an option, and was getting (what I thought) were strange results from .getOrElse. This was all occurring inside an Akka actor, and if the option was empty (None), then I wanted to send the actor's reply message. If there was a value (Some(str)), I wanted to assign the "x" to a value. The code looked something like this:
val result = returnsAnOptionString.getOrElse(self.reply(None))
The problem with the above statement is that when Some(str) comes back, the type of result was Any when I was expecting String.
I asked Paul Snively about this, and he kindly pointed me to the signature of getOrElse which looks like this:
def getOrElse [B >: A] (default: ⇒ B): B
Since Akka's Actor.reply returns an Any, and Any is a superclass of String, getOrElse(self.reply(None)) returns an Any.
So, the hunt was on for a better way to get x as a String. The most obvious way would be to tack .asInstanceOf[String] on the end, but that seems sort of ham-handed. The next most obvious solution would be to use a match like:
val result = { returnsAnOptionString match {
case Some(s:String) => s
case None => self.reply(None)
}}
self.reply(result + "12345")
There is a similar problem with the above statement. The val "result" still gets typed as Any. So, in this case, it looks like I want to do the entire processing of the Some(String) inside the case and just skip the assignment. Something like:
returnsAnOptionString match {
case Some(s:String) => { val result = s + "12345"; self.reply(result) }
case None => self.reply(None)
}
That will avoid the type issue with result, but I wanted to look for a better way. Paul mentioned using a "for comprehension" to process only the Some(String) possibility and ignore the None possibility. That could work something like this:
for ( s <- returnsAnOptionString ) self.reply(s + "12345")
self.reply(None)
That's pretty clean to my eyes, but Tony's blog post showed me that I could use foreach to simplify it a little bit more:
returnsAnOptionString.foreach(s => self.reply(s + "12345"))
self.reply(None)
Finally, Paul threw this one out for dealing with potentially null returns:
for { foo <- Option(someMethodThatCanReturnNull); bar <- somethingThatCantDealWitnNull(foo) } ...
So, I learned quite a bit about options this week. Hopefully this helps someone!

Yesterday, I was trying to unload an option, and was getting (what I thought) were strange results from .getOrElse. This was all occurring inside an Akka actor, and if the option was empty (None), then I wanted to send the actor's reply message. If there was a value (Some(str)), I wanted to assign the "x" to a value. The code looked something like this:
val result = returnsAnOptionString.getOrElse(self.reply(None))
The problem with the above statement is that when Some(str) comes back, the type of result was Any when I was expecting String.
I asked Paul Snively about this, and he kindly pointed me to the signature of getOrElse which looks like this:
def getOrElse [B >: A] (default: ⇒ B): B
My interpretation of this is that getOrElse returns something of type B where B has a lower bound of A, and takes a parameter named default that is defined as a "by-name" parameter of type B. In this case, A is String, so B is any superclass of String.
Since Akka's Actor.reply returns an Any, and Any is a superclass of String, getOrElse(self.reply(None)) returns an Any.
So, the hunt was on for a better way to get x as a String. The most obvious way would be to tack .asInstanceOf[String] on the end, but that seems sort of ham-handed. The next most obvious solution would be to use a match like:
val result = { returnsAnOptionString match {
case Some(s:String) => s
case None => self.reply(None)
}}
self.reply(result + "12345")
There is a similar problem with the above statement. The val "result" still gets typed as Any. So, in this case, it looks like I want to do the entire processing of the Some(String) inside the case and just skip the assignment. Something like:
returnsAnOptionString match {
case Some(s:String) => { val result = s + "12345"; self.reply(result) }
case None => self.reply(None)
}
That will avoid the type issue with result, but I wanted to look for a better way. Paul mentioned using a "for comprehension" to process only the Some(String) possibility and ignore the None possibility. That could work something like this:
for ( s <- returnsAnOptionString ) self.reply(s + "12345")
self.reply(None)
That's pretty clean to my eyes, but Tony's blog post showed me that I could use foreach to simplify it a little bit more:
returnsAnOptionString.foreach(s => self.reply(s + "12345"))
self.reply(None)
Finally, Paul threw this one out for dealing with potentially null returns:
for { foo <- Option(someMethodThatCanReturnNull); bar <- somethingThatCantDealWitnNull(foo) } ...
So, I learned quite a bit about options this week. Hopefully this helps someone!

No comments:
Post a Comment
Note: Only a member of this blog may post a comment.