3
votes

Suppose I have the following functions

def getHost():Option[String] = ...
def getPort():Option[Int] = ...

Now I would like to use defaults if these functions return None.

def makeURL() = {
  val host = getHost() getOrElse "localhost"
  val port = getPort() getOrElse 8080
  java.net.URL("http", host, port, "myPath")
}

Unfortunately this code does not look idiomatic in Scala. I would prefer makeURL to be more like a functions composition. How would you change makeURL?

3
Looks idiomatic to me.Rex Kerr

3 Answers

6
votes

I wouldn't change it. It's fine. The profit of this syntax is that it is concise.

Sure, you could change it with pure-mega-functional approach like this:

val host = getHost match {
  case Some(h) => h
  case None => "localhost"
}

But then you'd get four lines of code, instead of one.

3
votes

I agree with @serejja that what you've written is fine. However, if you feel like you MUST return an Option with a preset default:

 trait WithDefaults extends SomeBase{
   def defaultUrl = "localhost"

   abstract def makeURL() = withDefault(defaultUrl){ 
     super makeURL() 
   }

   protected def withDefault[A](default: A)(f: => Option[A]) = f match{
     case Some(v) => Some(v)
     case None => Some(default)
   }
 }

Stack a trait on it, then your interface never has to change and all your code will "just work" oblivious to the fact that there could be a default. Then again, this would also make you ask why it was an Option in the first place...

2
votes

Using getOrElse is already idiomatical, since you're pushing functionality instead of pulling it : instead of asking 'are you a None? if then do this otherwise do that' you're saying 'I want this done and if you don't have enough information use this default'.
If you're willing to use some scalaz, it looks a little bit nicer with the | operator:

 import scalaz._
 import Scalaz._


 def makeURL() = {
  val host = getHost() | "localhost"
  val port = getPort() | 8080
  java.net.URL("http", host, port, "myPath")
}