score:2

Accepted answer

I would use implicit parameter to pass default value. It will give you 100% type safety + easy way to override defaults not only for simple type, but for any other types.

  trait DefaultValue[T] {
    def default: T
  }

  object DefaultValue {
    def apply[T](value: T) = new DefaultValue[T] {
      val default: T = value
    }
  }

  trait LowLevelDefaultImplicits {
    implicit val intDefaultValue = DefaultValue[Int](0)
    implicit val booleanDefaultValue = DefaultValue[Boolean](false)
  }

  object MyDefaults extends LowLevelDefaultImplicits {
    // Easy to override defaults
    implicit val trueByDefault = DefaultValue[Boolean](true)
  }

  import MyDefaults._

  def readField(s: String): Any = ... some extern service call ...

  def getField[T: DefaultValue](fieldName: String): T =
  {
    val value = readField(fieldName)

    if (value == null)
      implicitly[DefaultValue[T]].default
    else
      value.asInstanceOf[T]
  }

  println(getField[Int]("aaa"))
  println(getField[Boolean]("aaa"))

Result:

0
true

^ - as you can see default "false" was overridden by higher priority implicit.

One drawback - you need to define defaults for all types T. But I think it's a benefit. By providing defaults for each type you get rid of 'null' values.

score:-1

You can always take an object oriented way:

case class GetField[A](default: A) {
  def apply(field: Any): A = try {
    field.asInstanceOf[A]
  } catch {
    case e: NullPointerException => ???
    case e: ClassCastException => default
  }
}

def readField(key: String): Any = ???

val field = readField("foo")
val bool = GetField(false)(field)
val int = GetField(0)(field)

score:-1

Simply use

value.asInstanceOf[T]

If value is null, this returns the default value of the type T. So 0 for numbers, false for booleans, and so on. This is specified somewhere in the Scala spec.


Related Query

More Query from same tag