Sami Dalouche Sami Dalouche - 1 year ago 48
Scala Question

Idiomatic way to use Options's in Scala

I am converting some Java code to Scala, trying to make the code as idiomatic as possible.

So, I now have some code using Options instead of nullable values, and I wonder whether things are scala'ish, or whether I'm wrong. So, could you guys please criticize the following snippet of code ?

The areas in which I am specifically looking for feedback are :

  • The use of a companion object as a factory, giving 2 options depending on whether we want to pass Options or Strings : is the String constructor fine, or should we always expose the fact that it is an Option ?

  • The use of preconditions : are there better ways to assert the fact that alpha3Code and name are mandatory, and a non-null option mustbe passed for alpha2Code ? (I am resorting to Guava for the string utils, as I haven't found anything in the Scala API)

  • The implementation of hashCode, equals and toString. equals and toString delegate to Guava again, whereas equals uses pattern matching. Is there a more scalish way ?

  • I know I could have used Case classes, which would have created default implementations, but I am mostly interested in learning how I should implement those for the cases where case classes cannot be used.

Thanks a lot !

package com.sirika.openplacesearch.api.language


object Language {
def apply(name : String, alpha3Code : String, alpha2Code : Option[String]) = new Language(name, alpha3Code, alpha2Code)
def apply(name : String, alpha3Code : String, alpha2Code : String = null) = new Language(name, alpha3Code, Option(alpha2Code))
def unapply(l : Language) = Some(, l.alpha3Code, l.alpha2Code )

class Language(val name : String, val alpha3Code : String, val alpha2Code : Option[String]) {
require(alpha2Code != null)

override def hashCode(): Int = Objects.hashCode(alpha3Code)

override def equals(other: Any): Boolean = other match {
case that: Language => this.alpha3Code == that.alpha3Code
case _ => false

override def toString() : String = Objects.toStringHelper(this)
.add("name", name)
.add("alpha3", alpha3Code)
.add("alpha2", alpha2Code)

Answer Source

I think you should expose only Option[String] in factory method. For example I, as a user of your library, will also ask myself question which factory method I should use. And most probably I will use Option.

Scala gives us enough tools to make our lifes easier. For example you can use default for option like this:

def apply(name: String, alpha3Code: String, alpha2Code: Option[String] = None) = 
 new Language(name, alpha3Code, alpha2Code)

If I, again as user of your library, want to pass just string without wrapping it in Some each time, I can write my own implicit conversion like this:

implicit def anyToOption[T](t: T): Option[T] = Some(t)

or even (if I personally use nulls):

implicit def anyToOption[T](t: T): Option[T] = 
 if (t == null) None else Some(t)

But I believe, if you enforce option, it will make your API more solid and clear.