Lucas Lima
Lucas Lima

Reputation: 902

How to compare the return type of a method to a Scala native or TypeTag?

So, I'm using the Scala reflections library, and I'm trying to check if a method conforms to a given type. To simplify, I'm trying to check only its output.

What I have now is:

val returnType = methodSymbol.returnType
// returnType: reflect.runtime.universe.Type = java.lang.String

So, I can read it is a String, but it has this terrible type reflect.runtime.universe.Type. How on Earth can I compare check if this return type is a simple String? I even tried using TypeTags, which are simple enough, but to convert a Type to a TypeTag is such a monumental effort that I fail to believe such a simple task cannot be achieved with more simply.

So, how can I compare this to a String and simply get a boolean back? I thought of simply calling a toString() and trying to parse that back to a normal type, but that would be really disgusting to do on the code, IMO. Also, I cannot simply specify the method name, because I'm working on a list of methods, and more will come later.

I've seen some questions, and even this (in my opinion, absurdly complex) answer on how to convert a Type to a TypeTag, but, again, I'm baffled by the level of complexity for such a trivial task. I'm already thinking of pulling my scarce hair out. Help appreciated.

EDIT: I've managed to make the comparison for the String itself, but not for a method returning the String.

To compare the String return type, I'm doing:

val returnType = methodSymbol.returnType
returnType =:= typeTag[String].tpe

When I try to check it with inheritance and a method, though, using <:<, it won't work. To clarify, B extends Trait A, the type signature is () => B, but I cannot match when coding

val typeSig = methodSymbol.typeSig
typeSig <:< typeTag[() => A].tpe

Upvotes: 2

Views: 279

Answers (2)

Dmytro Mitin
Dmytro Mitin

Reputation: 51683

If you want to work with types as Strings you should parse them

import scala.reflect.runtime.universe
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox

val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()
val str = "java.lang.String"
val tpe: Type = (tb.typecheck(tb.parse(s"type T = $str"), mode = tb.TYPEmode) match {
  case q"type T = $typ" => typ
}).tpe // String
tpe =:= typeOf[String] //true

(I would like to do just tb.typecheck(tb.parse(str/*, mode = ???*/), mode = tb.TYPEmode).tpe but can't find how to call TypeParser instead of TermParser with runtime reflection, this corresponds to difference between tq"..." and q"...", otherwise I get String companion instead of String itself. Surely tq"$str" gives wrong type too because it's a macro, it can work only for compile-time literals: tq"java.lang.String".)

Upvotes: 5

ELinda
ELinda

Reputation: 2821

Maybe not exactly what you're asking for, but you can use java.lang.reflect in Scala.

import java.lang.reflect.Method

class C {
  def doSomething(): String = {
    return "hello"
  }
  def doSomethingElse(): String = {
    return "bye"
  }
  def doNothing(): Int = {
    return 190
  }
}

val doSomethingMethod: Method = classOf[C].getMethods()(2)
val doNothingMethod: Method = classOf[C].getMethods()(1)
val doSomethingElseMethod: Method = classOf[C].getMethods()(0)

// false
doSomethingMethod.getReturnType.equals(doNothingMethod.getReturnType)

// true
doSomethingMethod.getReturnType.equals(doSomethingMethod.getReturnType)

// you can compare the simple name, too, if that's easier
println(s"'${doSomethingMethod.getReturnType.getSimpleName}'")
// 'String'

Upvotes: 5

Related Questions