0

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.

Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66
aij
  • 5,903
  • 3
  • 37
  • 41
  • 1
    Can you expand on exactly what you want? Maybe an example on how that should work? Also, how are you generating the code? Macros? Script? Scalameta? – Luis Miguel Mejía Suárez Jul 11 '19 at 14:02
  • 1
    Additionally to @LuisMiguelMejíaSuárez's questions, when do you generate code, at compile time or runtime? When does external code ("which may not be available yet") become available, at compile time or runtime? There're type ascription `1 : Int`, `asInstanceOf`, `typeOf`/`weakTypeOf`, `c.typecheck` ... – Dmytro Mitin Jul 11 '19 at 14:33
  • @LuisMiguelMejíaSuárez Added an example. The code is actually being generated from a Purescript script, long before Scala compilation is started. – aij Jul 11 '19 at 18:47
  • @DmytroMitin The code is being generated before it is compiled. If we were to integrate into SBT we would be using `sourceGenerators`. – aij Jul 11 '19 at 18:51
  • 1
    I think you are reinventing either **Macros** or **ScalaMeta**. Have you toke a look to them? – Luis Miguel Mejía Suárez Jul 11 '19 at 20:04
  • @aij 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))` – Dmytro Mitin Jul 12 '19 at 14:13

2 Answers2

4

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))
Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66
  • "It would be a type depending on arbitrary value, so we would have fully dependent types in Scala." It wouldn't depend on value, only on the expression's static type, which is fine... but it still doesn't exist in Scala. – Alexey Romanov Jul 12 '19 at 13:56
  • 1
    @AlexeyRomanov Actually I guess `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))` is close. – Dmytro Mitin Jul 12 '19 at 14:16
0

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
partha_devArch
  • 414
  • 2
  • 10
  • Unfortunately, `classOf[Class_Name]` is an expression, not a type. What I want is something equivalent to `Class_Name` but without needing to know the type in advance. – aij Jul 11 '19 at 18:55
  • I need some more details to help you on this. `object_name.getClass().getName` gives you the class name. And to parse the satement, you can use `classOf [Any]` if you donot know the class during compile time. – partha_devArch Jul 12 '19 at 07:23