0

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?

Andrey Tyukin
  • 43,673
  • 4
  • 57
  • 93
elaspog
  • 1,635
  • 3
  • 21
  • 51

2 Answers2

2

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.

Andrey Tyukin
  • 43,673
  • 4
  • 57
  • 93
  • Thanks, but as I've written, my case is much more complicated, so I can't do transforming the if-else expressions. I really need to store the value in a variable. – elaspog Jul 20 '18 at 13:48
  • @user1802693 See the update. `Type >: Null` enables you to start with `null` as default value. – Andrey Tyukin Jul 20 '18 at 13:49
2

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 
Dima
  • 39,570
  • 6
  • 44
  • 70