How to get the (static) type of an expression in Scala?

545 Views Asked by At

Does Scala have any equivalent to GCC's typeofextension? (Or C++ decltype?)

I'm generating code that references some external code (which may not be available yet), and I need a way to reference the type of that code in a method definition

For singleton objects, I could use Foo.type, but if Foo is an arbitrary expression, that doesn't work.

Update:

Here is a simplified example that shows the problem:

def f(x: typeof(Foo))(implicit M: Monoid[typeof(Foo)]) =
  M.append(Foo, M.append(x, Foo))

The code I am working on doesn't know anything about Foo other than that it is a string representation of a Scala expression. It is outputting the above code to a .scala file which is to be later compiled as part of a separate project.

Of course the typeof(Foo) bits don't work. Using Foo.type would work only if Foo is a singleton.

Basically, I want to know if there is something I could substitute in place of typeof(Foo) that would work for arbitrary Scala expressions.

2

There are 2 best solutions below

2
partha_devArch On

Do you have a reference class for the type you want to use? Else define a custom class, and use:

classOf [Class_Name] 

is equivalent typeOf

And if you re trying to know the class of your custom object, then use:

object_name.getClass
2
Dmytro Mitin On

In Scala there is no typeof of that sort.

We can try to modify the method adding type parameter

def f[F](foo: F)(x: F)(implicit M: Monoid[F]) =
  M.append(foo, M.append(x, foo))

and call it like f(Foo)(...), where Foo is the expression to be substituted, then F should be inferred upon compilation.

Otherwise I can imagine the following workflow. We could generate string represenation of the type of expression Foo from string represenation of Foo itself with Scalameta's SemanticDB and then insert string representation of expression Foo and this generated string represenation of the type.

One more option is to generate tree with macro annotation

import scala.annotation.StaticAnnotation
import scala.language.experimental.macros
import scala.reflect.macros.blackbox

class generate(foo: String) extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro generateMacro.impl
}

object generateMacro {
  def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
    import c.universe._
    val str: String = c.prefix.tree match {
      case q"new generate($s)" => c.eval[String](c.Expr(s))
    }
    val tree = c.typecheck(c.parse(str))
    val tpe = tree.tpe.widen
    annottees match {
      case q"$mods def $name[..$_](...$_): $_ = $_" :: _ =>
        q"""
            $mods def $name(x: $tpe)(implicit M: Monoid[$tpe]): $tpe =
              M.append($tree, M.append(x, $tree))
          """
    }
  }
}

@generate("1 + 1")
def f(): Unit = ()
// def f(x: Int)(implicit M: Monoid[Int]): Int = M.append(2, M.append(x, 2))

https://github.com/travisbrown/type-provider-examples/

https://docs.scala-lang.org/overviews/macros/typeproviders.html


Actually I guess this is close to what was asked

class TypeOf[A](a: A) {
  type T = A
}

val tp = new TypeOf(Foo)

def f(x: tp.T)(implicit M: Monoid[tp.T]) = M.append(Foo, M.append(x, Foo))