1
votes

I'd like to build a function to read the settings from a properties file, key/value pairs, and then cast it to expected types. If the given field name does't exist, we get the default value of the specific T. Is that doable?

I put some pseudo code here and would like to know how to write the real code with the help of scala reflection.

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

  if (value == null) {
    T match {
     case Int => 0
     case Boolean => false
     ...
     case _ => null
   }
  }
  else value.asInstanceOf[T]    
}

Alternatively, throw an exception if the field is not locate, which is not a bad idea to me... def getField[T](fieldName: String): T = { val value = getField(fieldName)

  if (value == null) {
    throw new Exception("error msg")
   }
  }
  else value.asInstanceOf[T]    
}

I know how to do it if it returns Option[T] (as discussed here Writing a generic cast function Scala ).

3

3 Answers

2
votes

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.

-1
votes

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)
-1
votes

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.