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._
// ...
Related
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
I have a package foo.bar in which a trait Parent is defined, and a series of objects Child1, Child2, Child3 are defined. I would like to get a List[Parent] containing all child objects defined in foo.bar. How can I write such a macro?
Right now I have the following:
def myMacro(c: blackbox.Context): c.Expr[Set[RuleGroup]] = {
val parentSymbol = c.mirror.staticClass("foo.bar.Parent")
c.mirror.staticPackage("foo.bar").info.members
// get all objects
.filter { sym =>
// remove $ objects
sym.isModule && sym.asModule.moduleClass.asClass.baseClasses.contains(parentSymbol)
}.map { ??? /* retrieve? */ }
???
}
I think this is what you'd be looking for:
.map(sym => c.mirror.reflectModule(sym.asModule).instance.asInstanceOf[Parent])
Later edit:
I have tried doing this in a trait, so not a macro like above, and when calling it with a different package than the one calling it from, it returned an empty collection of objects. Reading through it might have to do with how classloaders work in Scala as they don't have the knowledge of all the classes being loaded, but i see your macro doesn't use a classloader so maybe it still works in your case.
For me it worked using the Reflections library like this in a trait:
import org.reflections.Reflections
import scala.reflect.runtime.universe
import scala.reflect.{ClassTag, classTag}
import scala.collection.JavaConverters._
trait ChildObjects {
def childObjectsOf[Parent: ClassTag](containingPackageFullName: String): Set[Parent] = {
new Reflections(containingPackageFullName)
.getSubTypesOf(classTag[Parent].runtimeClass)
.asScala
.map(cls => {
val mirror = universe.runtimeMirror(cls.getClassLoader)
val moduleSymbol = mirror.moduleSymbol(cls)
mirror.reflectModule(moduleSymbol).instance.asInstanceOf[Parent]
})
.toSet
}
}
If the trait is not sealed you can't do that. Fundamentally if a trait is not sealed, it means new subclasses can be added later under different compilation unit.
If the trait is sealed, than you can use knownDirectSubclasses of ClassSymbolApi but beware of the possible issues the depend on order such as this and this in circe
I have the following object for making a conversion of an object ParsedItemDocument to a json String. I should note that ParsedItemDocument is a trait. My problem is that the implicit conversion that is called on the second snippet is not recognized by the compiler. Is there anything more that needs to be done for the implicit conversion to work?
import scala.language.implicitConversions
import wikidataParser.ParsedItemDocument
object Converters {
def toJson(obj: Any): String = {
val mapper = new ObjectMapper()
mapper.registerModule(DefaultScalaModule)
val out = new StringWriter
mapper.writeValue(out, obj)
return out.toString()
}
implicit def parsedItemDocumentToJsonString
(item: ParsedItemDocument): String = {
Converters.toJson(item)
}
}
Now, I use the following code-snippet in my code
import tools.Converters._
import wikidataParser.ParsedItemDocument
class WikipediaRankingTester2 extends FlatSpec {
"It" should "do something" in {
val jsonrdd:RDD[String]=rankedItems.map(t:Long,ParsedItemDocument)=>
t._2.parsedItemDocumentToJsonString)//compilation error here
}
}
You are mixing up implicit conversions and implicit classes.
If you want to use parsedItemDocumentToJsonString as a "method" of an object of type ParsedItemDocument, then you would need to define your implicit as
implicit class JSONParsing(item: ParsedItemDocument): String {
def parsedItemDocumentToJsonString = Converters.toJson(item)
}
If you declare it as an implicit conversion, as you did, then it means that you can call any methods of String on an object of type ParsedItemDocument, as the object will be implicitly converted to a String through the implicit method.
Also, it is not great practice to declare an entire implicit class / conversion, unless you 1) cannot add it to the original class, or 2) will be reusing the conversion very often, and it would save great amounts of code/readability. This does not seem to be the case here, as you are only wrapping in Converters.toJSON, which is not very verbose, and jsut as readable.
PS: your syntax in your "map" is wrong, the right syntax would be
val jsonrdd = rankedItems.map(t => t._2.parsedItemDocumentToJsonString)
If your implicit is working this should do it:
rankedItems.map(t => t._2)
You can test this by making the call explicit
rankedItems.map(t => parsedItemDocumentToJsonString(t._2))
If you want to add an extra method to a ParsedItemDocument you could use an implicit class, I don't think you need it but your code looks a bit that way.
In scala, I want to be able to say
val user = Node.create[User](...) // return User object
So here's what I have so far:
def create[T : TypeTag](map: Map[String, Any]) {
val type = typeOf[T]
// create class from type here???
}
I've been digging around how to create classes from generic types and found out that using ClassManifest seems to be deprecated. Instead, type tags are here, so I'm able to do something like this typeOf[T] and actually get the type.. but then I'm lost. If I could get the class, then I could use something like class.newInstance and manually set the fields from there.
Question is: given a type, can I get a class instance of the given type?
The easiest way in fact is to use ClassTag:
def create[T : ClassTag](map: Map[String, Any]): T = {
val clazz: Class[_] = classTag[T].runtimeClass
clazz.newInstance(<constructor arguments here>).asInstanceOf[T]
}
ClassTag is a thin wrapper around Java Class, primarily used for arrays instantiation.
TypeTag facility is more powerful. First, you can use it to invoke Java reflection:
import scala.reflect.runtime.universe._
def create[T: TypeTag](map: Map[String, Any]): T = {
val mirror = runtimeMirror(getClass.getClassLoader) // current class classloader
val clazz: Class[_] = mirror.runtimeClass(typeOf[T].typeSymbol.asClass)
clazz.newInstance(<constructor arguments here>).asInstanceOf[T]
}
However, Scala reflection allows to instantiate classes without dropping back to Java reflection:
def create[T: TypeTag](map: Map[String, Any]): T = {
// obtain type symbol for the class, it is like Class but for Scala types
val typeSym = typeOf[T].typeSymbol.asClass
// obtain class mirror using runtime mirror for the given classloader
val mirror = runtimeMirror(getClass.getClassLoader) // current class classloader
val cm = mirror.reflectClass(typeSym)
// resolve class constructor using class mirror and
// a constructor declaration on the type symbol
val ctor = typeSym.decl(termNames.CONSTRUCTOR).asMethod
val ctorm = cm.reflectConstructor(cm)
// invoke the constructor
ctorm(<constructor arguments here>).asInstanceOf[T]
}
If you want to create a class with overloaded constructors, it may require more work though - you'll have to select correct constructor from declarations list, but the basic idea is the same. You can read more on Scala reflection here
There is a way to do it with reflection: either runtime reflection, or in a macro. Regarding runtime reflection way, you can have a look at my blog post where I tried to do something like what you are trying to do now. Using compile-time reflection with macros might be a better option, depending on your need.
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.