Scala resolving Class/Type at runtime + type class constraint - scala

I have a generic function that require a HasMoveCapability implicit instance of the type T (type class pattern)
trait HasMoveCapability[T]
def doLogic[T: TypeTag: HasMoveCapability](): Unit = println(typeTag[T].tpe)
Then I have these two classes which have implicit instances for HasMoveCapability[T]
case class Bird()
object Bird {
implicit val hasMoveCapability = new HasMoveCapability[Bird]{}
}
case class Lion()
object Lion {
implicit val hasMoveCapability = new HasMoveCapability[Lion]{}
}
My question is the following:
I need to resolve the type (Lion or Bird) at runtime depending on an argument and call the function doLogic with the good type.
I tried
val input: String = "bird" // known at runtime
val resolvedType: TypeTag[_] = input match {
case "bird" => typeTag[Bird]
case "lion" => typeTag[Lion]
}
doLogic()(resolvedType) // doesn't compile
// `Unspecified value parameters: hasMoveCapability$T$1: HasMoveCapability[NotInferredT]`
What I would like to do is something like:
val resolvedType: TypeTag[_: HasMoveCapability] = input match{...}
The workaround that I am using so far is to call the function in the pattern match:
input match {
case "bird" => doLogic[Bird]
case "lion" => doLogic[Lion]
}
But by having many functions, the pattern match is getting duplicated and hard to maintain.
I am open to change the design if you have any suggestions :D

You should describe your problem better. Currently your type class HasMoveCapability doesn't seem to do anything useful. Currently what you do seems a hard way to transform the string "bird" into "Bird", "lion" into "Lion".
If you control the code of doLogic you seem not to need TypeTag. TypeTag / ClassTag is a way to persist information from compile time to runtime. You seem to do something in reverse direction.
Type classes / implicits are resolved at compile time. You can't resolve something at compile time based on runtime information (there is no time machine taking you from the future i.e. runtime to the past i.e. compile time). Most probably you need ordinary pattern matching rather than type classes (TypeTag, HasMoveCapability).
In principle you can run compiler at runtime, then you'll have new compile time inside runtime, and you'll be able to infer types, resolve implicits etc.
import scala.tools.reflect.ToolBox
import scala.reflect.runtime.currentMirror
import scala.reflect.runtime.universe.{TypeTag, typeTag}
object App {
trait HasMoveCapability[T]
def doLogic[T: TypeTag: HasMoveCapability](): Unit = println(typeTag[T].tpe)
case class Bird()
object Bird {
implicit val hasMoveCapability = new HasMoveCapability[Bird]{}
}
case class Lion()
object Lion {
implicit val hasMoveCapability = new HasMoveCapability[Lion]{}
}
val input: String = "bird" // known at runtime
val tb = currentMirror.mkToolBox()
tb.eval(tb.parse(s"import App._; doLogic[${input.capitalize}]")) //App.Bird
def main(args: Array[String]): Unit = ()
}
scala get generic type by class

Related

Scala 3 Macro - Retain a generic type in runtime

I'm looking for an option to retain a generic type in runtime in Scala3. In Scala2 there was a TypeTag for this, however, now it is removed and the suggested option is to use macros (https://contributors.scala-lang.org/t/scala-3-and-reflection/3627).
The documentation, however, is somewhat cryptic...
This is what I'm trying to do:
Here's a macro implementation:
object TestMacroImpl {
def getClassImpl[T](using Quotes)(using t: Type[T]): Expr[Class[T]] = '{
classOf[${t}]
}
}
Here's a macro:
import macros.TestMacro.getClassMacro
class TypedBox[T] {
val staticClass: Class[T] = TypedBox.getStaticClass[T]
}
object TypedBox {
inline def getStaticClass[T] = ${ getClassMacro[T] }
}
Test:
object Test {
def main(args: Array[String]): Unit = {
val stringBox = TypedBox[String]()
println(stringBox.staticClass)
}
}
I would envision this to be resolved as val staticClass = classOf[String]
But this does not compile, I'm getting:
/workspace/macros-test/src/main/scala/macros/TestMacro.scala:7:13
t.Underlying is not a class type
classOf[${t}]
What am I missing?
Not really sure why but I don't think you can reliably get an Expr[Class[T]] out of macros (from what I understood, it could be that the Class does not yet exist at the time of macro execution).
Plus, a Class[T] does not retain the parameterized types: classOf[Map [String, String]] = classOf[Map[Int, Int]] for instance.
If you don't care about them, I'd use a ClassTag instead of TypeTag which is still available in Scala 3. And no need for macros.
By the way, in macros, you can write something like the following to get a Expr[ClassTag[T]]:
private def getClassTag[T](using Type[T], Quotes): Expr[ClassTag[T]] = {
import quotes.reflect._
Expr.summon[ClassTag[T]] match {
case Some(ct) =>
ct
case None =>
report.error(
s"Unable to find a ClassTag for type ${Type.show[T]}",
Position.ofMacroExpansion
)
throw new Exception("Error when applying macro")
}
}
Finally, you might find some useful things at https://github.com/gaeljw/typetrees/blob/main/src/main/scala/io/github/gaeljw/typetrees/TypeTreeTagMacros.scala#L8 (disclaimer: I wrote it for personal projects).

Is there anyway, in Scala, to get the Singleton type of something from the more general type?

I have a situation where I'm trying to use implicit resolution on a singleton type. This works perfectly fine if I know that singleton type at compile time:
object Main {
type SS = String with Singleton
trait Entry[S <: SS] {
type out
val value: out
}
implicit val e1 = new Entry["S"] {
type out = Int
val value = 3
}
implicit val e2 = new Entry["T"] {
type out = String
val value = "ABC"
}
def resolve[X <: SS](s: X)(implicit x: Entry[X]): x.value.type = {
x.value
}
def main(args: Array[String]): Unit = {
resolve("S") //implicit found! No problem
}
}
However, if I don't know this type at compile time, then I run into issues.
def main(args: Array[String]): Unit = {
val string = StdIn.readLine()
resolve(string) //Can't find implicit because it doesn't know the singleton type at runtime.
}
Is there anyway I can get around this? Maybe some method that takes a String and returns the singleton type of that string?
def getSingletonType[T <: SS](string: String): T = ???
Then maybe I could do
def main(args: Array[String]): Unit = {
val string = StdIn.readLine()
resolve(getSingletonType(string))
}
Or is this just not possible? Maybe you can only do this sort of thing if you know all of the information at compile-time?
If you knew about all possible implementations of Entry in compile time - which would be possible only if it was sealed - then you could use a macro to create a map/partial function String -> Entry[_].
Since this is open to extending, I'm afraid at best some runtime reflection would have to scan the whole classpath to find all possible implementations.
But even then you would have to embed this String literal somehow into each implementations because JVM bytecode knows nothing about mappings between singleton types and implementations - only Scala compiler does. And then use that to find if among all implementations there is one (and exactly one) that matches your value - in case of implicits if there are two of them at once in the same scope compilation would fail, but you can have more than one implementation as long as the don't appear together in the same scope. Runtime reflection would be global so it wouldn't be able to avoid conflicts.
So no, no good solution for making this compile-time dispatch dynamic. You could create such dispatch yourself by e.g. writing a Map[String, Entry[_]] yourself and using get function to handle missing pices.
Normally implicits are resolved at compile time. But val string = StdIn.readLine() becomes known at runtime only. Principally, you can postpone implicit resolution till runtime but you'll be able to apply the results of such resolution at runtime only, not at compile time (static types etc.)
object Entry {
implicit val e1 = ...
implicit val e2 = ...
}
import scala.reflect.runtime.universe._
import scala.reflect.runtime
import scala.tools.reflect.ToolBox
val toolbox = ToolBox(runtime.currentMirror).mkToolBox()
def resolve(s: String): Any = {
val typ = appliedType(
typeOf[Entry[_]].typeConstructor,
internal.constantType(Constant(s))
)
val instanceTree = toolbox.inferImplicitValue(typ, silent = false)
val instance = toolbox.eval(toolbox.untypecheck(instanceTree)).asInstanceOf[Entry[_]]
instance.value
}
resolve("S") // 3
val string = StdIn.readLine()
resolve(string)
// 3 if you enter S
// ABC if you enter T
// "scala.tools.reflect.ToolBoxError: implicit search has failed" otherwise
Please notice that I put implicits into the companion object of type class in order to make them available in the implicit scope and therefore in the toolbox scope. Otherwise the code should be modified slightly:
object EntryImplicits {
implicit val e1 = ...
implicit val e2 = ...
}
// val instanceTree = toolbox.inferImplicitValue(typ, silent = false)
// should be replaced with
val instanceTree =
q"""
import path.to.EntryImplicits._
implicitly[$typ]
"""
In your code import path.to.EntryImplicits._ is import Main._.
Load Dataset from Dynamically generated Case Class

Importing generic implicits from class instances

I'm trying to make a generic implicit provider which can create an implicit value for a given type, something in the lines of:
trait Evidence[T]
class ImplicitProvider[T] {
class Implementation extends Evidence[T]
implicit val evidence: Evidence[T] = new Implementation
}
To use this implicit, I create a val provider = new ImplicitProvider[T] instance where necessary and import from it import provider._. This works fine as long as there is just one instance. However sometimes implicits for several types are needed in one place
case class A()
case class B()
class Test extends App {
val aProvider = new ImplicitProvider[A]
val bProvider = new ImplicitProvider[B]
import aProvider._
import bProvider._
val a = implicitly[Evidence[A]]
val b = implicitly[Evidence[B]]
}
And this fails to compile with could not find implicit value for parameter and not enough arguments for method implicitly errors.
If I use implicit vals from providers directly, everything starts to work again.
implicit val aEvidence = aProvider.evidence
implicit val bEvidence = bProvider.evidence
However I'm trying to avoid importing individual values, as there are actually several implicits inside each provider and the goal is to abstract them if possible.
Can this be achieved somehow or do I want too much from the compiler?
The issue is that when you import from both objects, you're bringing in two entities that have colliding names: evidence in aProvider and evidence in bProvider. The compiler cannot disambiguate those, both because of how its implemented, and because it'd be a bad idea for implicits, which can already be arcane, to be able to do things that cannot be done explicitly (disambiguating between clashing names).
What I don't understand is what the point of ImplicitProvider is. You can pull the Implementation class out to the top level and have an object somewhere that holds the implicit vals.
class Implementation[T] extends Evidence[T]
object Evidence {
implicit val aEvidence: Evidence[A] = new Implementation[A]
implicit val bEvidence: Evidence[B] = new Implementation[B]
}
// Usage:
import Evidence._
implicitly[Evidence[A]]
implicitly[Evidence[B]]
Now, there is no name clash.
If you need to have an actual ImplicitProvider, you can instead do this:
class ImplicitProvider[T] { ... }
object ImplicitProviders {
implicit val aProvider = new ImplicitProvider[A]
implicit val bProvider = new ImplicitProvider[B]
implicit def ImplicitProvider2Evidence[T: ImplicitProvider]: Evidence[T]
= implicitly[ImplicitProvider[T]].evidence
}
// Usage
import ImplicitProviders._
// ...

TypeTag for case classes

I would like to make a case class Bla that takes a type parameter A and it knows the type of A at runtime (it stores it in its info field).
My attempt is shown in the example below. The problem is that this example does not compile.
case class Bla[A] (){
val info=Run.paramInfo(this) // this does not compile
}
import scala.reflect.runtime.universe._
object Run extends App{
val x=Bla[Int]
def paramInfo[T](x:T)(implicit tag: TypeTag[T]): String = {
val targs = tag.tpe match { case TypeRef(_, _, args) => args }
val tinfo=s"type of $x has type arguments $targs"
println(tinfo)
tinfo
}
paramInfo(x)
}
However when I comment val info=Run.paramInfo(this) then the program runs fine and prints:
type of Bla() has type arguments List(Int)
Is there a way to make this example below compile ? (or in some other way achieve the same goal, i.e. that a case class is self aware of the type of it's type parameter?)
There's little point in using reflection based APIs for this, shapeless has a typeclass that exposes compile time information to runtime using an implicit macro.
import shapeless.Typeable
class Test[T : Typeable] {
def info: String = implicitly[Typeable[T]].describe
}
It's also relatively easy to roll your own thing here, with the added inconvenience of having to compile the implicit macro in a different compilation unit than whatever is using it.
You just need to pass the implicit type tag parameter to the case class constructor (otherwise the type information is lost before calling paraInfo which requires it):
case class Bla[A : TypeTag]() { ... }
Which is shorthand for:
case class Bla[A](implicit tag: TypeTag[A]) { ... }

Scala bring value into implicit scope without naming it

When using spray-json, I need to bring a JsonFormat[A] into implicit scope for every domain type A that I want to serialize.
The recommended approach is to create a custom object with all the implicits as fields:
object MyJsonProtocol extends DefaultJsonProtocol {
implicit val colorFormat = jsonFormat4(Color)
}
import MyJsonProtocol._
My app has a great many domain types, some of which have long names. My MyJsonProtocol is getting long and unreadable:
object MyJsonProtocol extends DefaultJsonProtocol {
... // many more here
implicit val someClassWithALongNameFormat = jsonFormat4(SomeClassWithALongName)
implicit val someClassWithALongNameInnerFormat = jsonFormat4(SomeClassWithALongNameInner)
implicit val someClassWithALongNameVariantBFormat = jsonFormat4(SomeClassWithALongNameVariantB)
... // many more here
}
The long val names have various problems:
they feel redundant (the names are never read)
they make my lines very long
they introduce a copy/paste risk that the name of the format won't match the type of the format
they make the RHS values not aligned, which hides the common pattern here
Is there any way to bring an object into implicit scope without naming it? Something like this would be much neater:
object MyJsonProtocol extends DefaultJsonProtocol {
... // many more here
implicit val _ = jsonFormat4(SomeClassWithALongName)
implicit val _ = jsonFormat4(SomeClassWithALongNameInner)
implicit val _ = jsonFormat4(SomeClassWithALongNameVariantB)
... // many more here
}
... but Scala doesn't allow multiple fields named "_".
Is there any way to bring these formats into implicit scope without naming them all? Is there another way to use spray-json that avoids this issue?
Normally, I define typeclass instances in the companion objects:
case class Foo()
object Foo {
implicit val jsonFormatter = new JsonFormat[Foo] { ... }
}
case class Bar()
object Bar {
implicit val jsonFormatter = new JsonFormat[Bar] { ... }
}
I don't have to import anything, as companion objects are by default included in the implicit search scope, and the implicit members can all have the same names.