I wrote this slick code and it works as expected
object TestApp extends App {
implicit val getFooResult = GetResult(r => Foo(r.<<, r.<<))
val query = sql"select a, b from foo".as[Foo]
}
case class Foo(a: Long, b: String)
This compiles and runs fine. but If I change the code to
object TestApp extends App with MyImplicits {
val query = sql"select a, b from foo".as[Foo]
}
trait MyImplicits {
implicit val getFooResult = GetResult(r => Foo(r.<<, r.<<))
}
case class Foo(a: Long, b: String)
Now I get a compile error
could not find implicit value for parameter rconv: slick.jdbc.GetResult[Foo]
Same thing happens when I try
object TestApp extends App {
import MyImplicits.getFooResult
val query = sql"select a, b from foo".as[Foo]
}
object MyImplicits {
implicit val getFooResult = GetResult(r => Foo(r.<<, r.<<))
}
case class Foo(a: Long, b: String)
It still gives the same error and does not see that the implicit is defined in the object.
Why am I loosing the visibility to the implicit when I move it in a trait or object?
Related
I have an implicit class that needs to use a given parameter at runtime. So I define this implicit in another class that takes this parameter in the constructor. A simplified version of what I am doing is as follows:
case class A(p1: String) {
def foo = println("foo: " + p1)
}
class B(p2: String) {
implicit class Enhancer(a: A) {
implicit def bar = s"bar: ${a.p1}, $p2"
}
}
So when I need to use this class I then do the following:
val a = A("x")
val b = new B("y")
import b._
a.bar
I am wondering if there is a neater way than the above? Specifically the middle two lines where I define the object and then import from it. For example is there any way I could have a one line call to return the implicit class I need?
Try to add implicit parameter to Enhancer.
case class A(p1: String) {
def foo = println("foo: " + p1)
}
class B(val p2: String)
implicit class Enhancer(a: A)(implicit b: B) {
implicit def bar = s"bar: ${a.p1}, ${b.p2}"
}
val a = A("x")
implicit object b extends B("y")
a.bar
or
implicit val b = new B("y")
a.bar
Or
implicit class Enhancer(val a: A) extends AnyVal {
implicit def bar(implicit b: B) = s"bar: ${a.p1}, ${b.p2}"
}
I very roughly have the following code:
object MyObj {
def callWithParams(params: List[Param]): String = "some string"
}
sealed trait Param
case class Single(id: Int) extends Param
case class Group(id: Int, subParams: List[Param]) extends Param
def buildMyParams(): List[Param] = List(Single(1), Group(2, List(Group(3, Single(4))))
def macroImpl(c: blackbox.Context): c.Expr[String] = {
import c.universe._
// TODO: need a implicit Lift[Param] implementation here
val myParams = buildMyParams()
c.Expr[String](q"MyObj.callWithParams($myParams)")
}
My attempt at the implicit List[Param] is:
implicit val lift = Liftable[Param]({
case s: Single => q"Single(${s.id})"
case g: Group => q"Group(${g.id}, ${g.subParams})"
})
This doesn't compile because of the forward reference in the Liftable when trying to lift a Group, because of Group.subParams.
How do I get around this issue?
Declaring the lift as a def rather than a val was enough to fix this:
implicit def lift = Liftable[Param]({
case s: Single => q"Single(${s.id})"
case g: Group => q"Group(${g.id}, ${g.subParams})"
})
Consider this code:
sealed trait Data
case class StringData(string: String) extends Data
case class IntData(int: Int) extends Data
trait Reader[A] {
def read(data: Data): A
}
implicit val stringReader: Reader[String] = {
case StringData(string) => string
case _ => sys.error("not a string")
}
implicit val intReader: Reader[Int] = {
case IntData(int) => int
case _ => sys.error("not an int")
}
With this in scope, I want to write an implicit method that silently converts from Data values to their "real" Scala values.
implicit def fromData[A: Reader](data: Data): A =
implicitly[Reader[A]].read(data)
But then, this code does not compile:
val str: String = StringData("foo")
val int: Int = IntData(420)
The error is a type mismatch. Standard debugging methods for implicits show that the A from fromData can't be infered (all implicit Readers are shown as applicable).
For your convenience, this is a link to a scastie of the code. In this other scastie, a similiar, yet different, and working snippet is presented.
My question: What is going on here?
Making the change to your Data class as well as your reader implicit conversion as below allows the code to compile.
import scala.language.implicitConversions
sealed trait Data[A]
case class StringData(string: String) extends Data[String]
case class IntData(int: Int) extends Data[Int]
trait Reader[A] {
def read(data: Data[A]): A
}
implicit val stringReader: Reader[String] = {
case StringData(string) => string
case _ => sys.error("not a string")
}
implicit val intReader: Reader[Int] = {
case IntData(int) => int
case _ => sys.error("not an int")
}
implicit def fromData[A](data: Data[A])(implicit ev: Reader[A]): A = ev.read(data)
val str: String = StringData("foo")
val int: Int = IntData(420)
You need data to be typed so that the compiler can infer which Reader should be used based on the type parameter of Data. Also notice that the following would not compile if you did not define an implicit Reader.
case class DoubleData(d: Double) extends Data[Double]
// Fails compilation because no implicit Reader exists.
val d: Double = DoubleData(5d)
What I'm trying to do is: get an implicit instance from the class name.
The main problem that I can't get an implicit instance for a class type that created at runtime.
What I have:
trait Base
case class A() extends Base
case class B() extends Base
trait Worker[T <: Base] {
def foo(t: T): Unit
}
implicit val workerA = new Worker[A] {
def foo(a: A): Unit = ??? // do some A specific work
}
implicit val workerB = new Worker[B] {
def foo(b: B): Unit = ??? // do some B specific work
}
What I want to do: somehow get an implicit instance from the class name.
trait TypeHolder {
type Typed <: Base
}
def getClassType(className: String): TypeHolder = className match {
case "A" => new TypeHolder {
type Typed = A
}
case "B" => new TypeHolder {
type Typed = B
}
}
def getWorker(typeHolder: TypeHolder)(implicit worker: Worker[typeHolder.Typed]): Worker[typeHolder.Typed] = worker
val className: String = ConfigFactory.load().getString("class-name")
val worker = getWorker(getClassType(className))
Error: could not find implicit value for parameter worker: Worker[typeHolder.Typed]
val worker = getWorker(getClassType(className))
That's impossible.
Implicit resolution is resolved at compile time: it can't be influence by a runtime value.
I have createOld method that I need to override and I cannot change it. I would like to use TypeTag to pattern match provided type in createNew. The goal is to find out how to call createNew from createOld. My current understanding is that compiler doesn't have enough type information about A in createOld method if it doesn't already come with TypeTag[A].
object TypeTagFromClass {
class C1
class C2
// How to get TypeTag[A] needed by createNew?
def createOld[A](c: Class[A]): A = createNew ???
def createNew[A : TypeTag]: A = {
val result = typeOf[A] match {
case a if a =:= typeOf[C1] => new C1()
case a if a =:= typeOf[C2] => new C2()
}
result.asInstanceOf[A]
}
}
It is possible to create a TypeTag from a Class using Scala reflection, though I'm not sure if this implementation of TypeCreator is absolutely correct:
import scala.reflect.runtime.universe._
def createOld[A](c: Class[A]): A = createNew {
val mirror = runtimeMirror(c.getClassLoader) // obtain runtime mirror
val sym = mirror.staticClass(c.getName) // obtain class symbol for `c`
val tpe = sym.selfType // obtain type object for `c`
// create a type tag which contains above type object
TypeTag(mirror, new TypeCreator {
def apply[U <: Universe with Singleton](m: api.Mirror[U]) =
if (m eq mirror) tpe.asInstanceOf[U # Type]
else throw new IllegalArgumentException(s"Type tag defined in $mirror cannot be migrated to other mirrors.")
})
}
However, you don't really need full TypeTag if you don't need to inspect generic parameters and full Scala type information. You can use ClassTags for that:
def createNew[A: ClassTag]: A = {
val result = classTag[A].runtimeClass match {
case a if a.isAssignableFrom(classOf[C1]) => new C1()
case a if a.isAssignableFrom(classOf[C2]) => new C2()
}
result.asInstanceOf[A]
}
Or with some implicit sugar:
implicit class ClassTagOps[T](val classTag: ClassTag[T]) extends AnyVal {
def <<:(other: ClassTag[_]) = classTag.runtimeClass.isAssignableFrom(other.runtimeClass)
}
def createNew[A: ClassTag]: A = {
val result = classTag[A] match {
case a if a <<: classTag[C1] => new C1()
case a if a <<: classTag[C2] => new C2()
}
result.asInstanceOf[A]
}
You can simplify that even further by using plain old Java newInstance() method:
def createNew[A: ClassTag]: A = classTag[A].runtimeClass.newInstance().asInstanceOf[A]
This, of course, would only work if you don't need different constructor parameters for different classes.
Calling this createNew from createOld is much simpler than the one with TypeTags:
def createOld[A](c: Class[A]): A = createNew(ClassTag[A](c))
So it is not very safe and correct (cause you don't use the power of scala type system), but you can make (using your logic) to do the following:
def createNew[A](implicit t: TypeTag[A]): A = {
val result: Any = t.tpe.toString match {
case "C1" => new C1
case "C2" => new C2
}
result.asInstanceOf[A]
}
createNew[C1] //> its all ok
createNew[C2] //> its all ok
createNew[C3] //> crashes here; lets pretend we got C3 class
To use it with createOld, just pass implicit argument:
def createOld[A](c: Class[A])(implicit t: TypeTag[A]): A = createNew[A]
createOld[C1] //> its all ok
createOld[C2] //> its all ok
createOld[C3] //> crashes here; lets pretend we got C3 class
I think I should not tell you twice that it is not very good.
We can improve this code by using shapeless:
Lets create a poly function, which has a TypeTag as an argument:
import shapeless._; import scala.reflect.runtime.universe._;
def getTypeTag[T](implicit t: TypeTag[T]) = t //> to get TypeTag of a class
// here is low prority implicit
trait createPolyNewErr extends Poly1 {
implicit def newErr[T] = at[T](_ => "Error can not create object of this class")
}
object createPolyBew extends createPolyNewError {
implicit def newC1 = at[TypeTag[C1]](_ => new C1)
implicit def newC2 = at[TypeTag[C2]](_ => new C2)
}
createPolyNew(getTypeTag[C1]) //> success
createPolyNew(getTypeTag[C2]) //> success
createPolyNew(getTypeTag[C3]) //> String: Error can not create object of this class no crash!
We also can write a function, in order not to use function getTypeTag[T] every time:
def createPoly[T]
(implicit t: TypeTag[T],
cse: poly.Case[createPolyNew.type, TypeTag[T] :: HNil]) = cse(t)
createPoly[C1] //> its all ok
createPoly[C2] //> its all ok
createPoly[C3] //> String: Error can not create object of this class no crash!