How to initialize variable of Type in Scala?

402 Views Asked by At

I'm new to scala, sorry for the dumb question. I want to remove the return statements from this Scala code (my real case is much more complicated than this)

def readValue[Type](value: Any)(implicit tag: ClassTag[Type]): Type = {

    if (value == null) { 
      return null.asInstanceOf[Type] 
    } else {
      if (classOf[URL].isAssignableFrom(tag.runtimeClass)) {
        return new URL(value.toString).asInstanceOf[Type]
      }
      if (classOf[URI].isAssignableFrom(tag.runtimeClass)) {
        return new URI(value.toString).asInstanceOf[Type]
      }
      null.asInstanceOf[Type]
    }
}

that's why I want to store the return value of a Type instance, like this:

def readValue[Type](value: Any)(implicit tag: ClassTag[Type]): Type = {

    var retVal:Type = null
    if (value == null) { 
       // retVal=...
    } 
    else { 
       // if cond: retVal=...
    }
    retVal
}

The solution above does not compile. How could I initialize the variable for type Type?

2

There are 2 best solutions below

2
On

if-elses are expressions, not just statements in scala:

def readValue[Type](value: Any)(implicit tag: ClassTag[Type]): Type = {
    if (value == null) { 
      null.asInstanceOf[Type] 
    } else if (classOf[URL].isAssignableFrom(tag.runtimeClass)) {
      new URL(value.toString).asInstanceOf[Type]
    } else if (classOf[URI].isAssignableFrom(tag.runtimeClass)) {
      new URI(value.toString).asInstanceOf[Type]
    } else {
      null.asInstanceOf[Type]
    }
}

Also note that classOf[A].isAssignableFrom(classOf[B]) means that a value b of type B can be downcast to b.asInstanceOf[A], not the other way round. If classOf[URL].isAssignableFrom(tag.runtimeClass), then you are allowed to cast a value of type Type into URL, not the other way round.

Moreover, your code would work if you restricted the argument Type to Type >: Null.

0
On

Something like this perhaps:

 Option(value)
   .map { _.toString }
   .map { v =>  tag.runtimeClass.getConstructor(v.getClass).newInstance(v) }
   .map { _.asInstanceOf[Type] }
   .orNull

Or this if you prefer to avoid reflection:

val contructors: Map[Class[_], String => Any] = Map(
  classOf[URL] -> { s => new URL(s) }
  classOf[Uri] -> { s => new URI(s) }
}

Option(value)
 .map { _.toString }
 .map { constructors(tag.runtimeClass).apply(_) }
 .map { _.asInstanceOf[Type] }
 .orNull