How to require at compile time that a type parameter be a trait (and not a class or other type value)?
Asked Answered
N

2

5

I'm looking for some kind of upper bound on a generic parameter T that ensures that T is a trait.

class Foo
trait Bar

def f[A ??? IsATrait] = ???

// f[Foo] Won't compile
f[Bar] // this is fine
Nealneala answered 26/5, 2019 at 8:37 Comment(6)
Not sure is if this is possible, what is your use case for this?Tollmann
Please, read meta.stackexchange.com/a/183183/2988 and softwareengineering.meta.stackexchange.com/q/7273/1352 to understand why "Is it possible" type questions are off-topic on Stack Overflow (and most of Stack Exchange).Taoism
@JörgWMittag: I'll reword it.Nealneala
@Harald: I have a generic class with type parameter A. I want to a write a generic method with type parameter B that would only compile if the run-time type of A is a subtype of B. This is of course, possible if A <: B but it's also possible for some type C extends A with B if B is a trait, but otherwise it's not possible, e.g., if A =:= Int and B =:= String.Nealneala
@Nealneala If that's the requirement then it's possible for any non-AnyVal classes, not just for traits (because of null). And for compound types. And probably for others...Elgon
@AlexeyRomanov You're right, but for now checking if it's a trait is good enough for me.Nealneala
F
12

Try

typeOf[Bar].typeSymbol.asClass.isTrait // true
typeOf[Foo].typeSymbol.asClass.isTrait // false

At compile time

import scala.language.experimental.macros
import scala.reflect.macros.whitebox

trait IsATrait[A]

object IsATrait { 
  implicit def materialize[A]: IsATrait[A] = macro impl[A]

  def impl[A: c.WeakTypeTag](c: whitebox.Context): c.Tree = {
    import c.universe._
    val tpA = weakTypeOf[A]
    if (tpA.typeSymbol.asClass.isTrait)
      q"new IsATrait[$tpA] {}"
    else c.abort(c.enclosingPosition, s"$tpA is not a trait")
  }
}

def f[A: IsATrait] = ???

f[Bar] // compiles

f[Foo]
//Information: IsATrait.materialize is not a valid implicit value for IsATrait[Foo] because:
//             hasMatchingSymbol reported error: Foo is not a trait
//
//Error: could not find implicit value for evidence parameter of type IsATrait[Foo]
//
//Error: not enough arguments for method f: (implicit evidence$1: IsATrait[Foo])Nothing.
//       Unspecified value parameter evidence$1.
Followthrough answered 26/5, 2019 at 11:28 Comment(4)
Not as "clean" as I would have hoped but apparently there's no first-class support for it. Thanks!Nealneala
Is it possible to extend to check to also include Java interfaces? I only found isJava, which of course also includes regular classes.Nealneala
@Nealneala Not sure what you want. My code works for Java interfaces as well.Followthrough
Nevermind, it was my mistake. I'm a macro newbie and forgot to properly import the macro in my use-site.Nealneala
V
-5

Is it possible to require at compile time that a type parameter is a trait (and not a class or other type value)?

No.

Venessavenetia answered 26/5, 2019 at 9:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.