I want to define circular referenced structure JSON with spray-json, so I try to define like below.
final case class A(b: B)
final case class B(a: A)
trait AProtocol extends DefaultJsonProtocol {
implicit val aProtocol: RootJsonFormat[A] = rootFormat(lazyFormat(jsonFormat1(A)))
}
But I got an error which is
<console>:18: error: could not find implicit value for evidence parameter of type MyProtocol.this.JF[B]
implicit val aProtocol: RootJsonFormat[A] = rootFormat(lazyFormat(jsonFormat1(A)))
Please give me some advices.
Well, you have jsonFormat for A but what with B. You are using lazyFormat well but completely forgot about other dependency. Try this:
final case class A(b: B)
final case class B(a: A)
trait AProtocol extends DefaultJsonProtocol {
implicit val aProtocol: RootJsonFormat[A] = rootFormat(lazyFormat(jsonFormat1(A)))
implicit val bProtocol: RootJsonFormat[B] = rootFormat(lazyFormat(jsonFormat1(B)))
}
Related
I am performing a repetitive task of creating a object that has same internal contents and hence thought of creating a generic method that would help me achieve this.
The internal object is as follows
case class Data(value: Int)
I have a base trait as follows
trait Base
There are a couple of classes that extend this trait
case class A(data: Data) extends Base
case class B(data: Data) extends Base
case class C(data: Data) extends Base
The generic method that I am trying to write to create the object
def getObject[T <: Base](data: Data, t: T) = {
T(data)
}
However, while trying to do so, I get a compile-time error saying that
Cannot resolve symbol T
Can you please let me know what I am missing in this method implementation.
Note:- This is a very simplistic implementation of what I am trying to do in my code.
Due to type-erasure, you can't use generic type to create a new instance of an object.
You could use ClassTag to capture a class of T at runtime:
case class Data(value: Int)
trait Base
case class A(data: Data) extends Base
case class B(data: Data) extends Base
case class C(data: Data) extends Base
def getObject[T <: Base](data: Data)(implicit ct: ClassTag[T]): T =
ct.runtimeClass.getDeclaredConstructors.head.newInstance(data).asInstanceOf[T]
val a: A = getObject[A](Data(1))
val b: B = getObject[B](Data(2))
val c: C = getObject[C](Data(3))
As cchantep noticed, it has a drawback, that if your case class doesn't have a constructor with single argument Data, this function will fail at runtime.
Consider typeclass solution for compile-time safety
final case class Data(value: Int)
final case class A(data: Data)
final case class B(data: Data)
final case class C(data: Data)
trait BaseFactory[T] {
def apply(data: Data): T
}
object BaseFactory {
def apply[T](data: Data)(implicit ev: BaseFactory[T]): T = ev.apply(data)
implicit val aBaseFactory: BaseFactory[A] = (data: Data) => A(data)
implicit val bBaseFactory: BaseFactory[B] = (data: Data) => B(data)
implicit val cBaseFactory: BaseFactory[C] = (data: Data) => C(data)
}
val data = Data(42)
BaseFactory[A](data) // res0: A = A(Data(42))
BaseFactory[B](data) // res1: B = B(Data(42))
BaseFactory[C](data) // res2: C = C(Data(42))
I'm running into an issue where I am working with several Traits that use dependent typing, but when I try to combine the Traits in my business logic, I get a compilation error.
import java.util.UUID
object TestDependentTypes extends App{
val myConf = RealConf(UUID.randomUUID(), RealSettings(RealData(5, 25.0)))
RealConfLoader(7).extractData(myConf.settings)
}
trait Data
case class RealData(anInt: Int, aDouble: Double) extends Data
trait MySettings
case class RealSettings(data: RealData) extends MySettings
trait Conf {
type T <: MySettings
def id: UUID
def settings: T
}
case class RealConf(id: UUID, settings: RealSettings) extends Conf {
type T = RealSettings
}
trait ConfLoader{
type T <: MySettings
type U <: Data
def extractData(settings: T): U
}
case class RealConfLoader(someInfo: Int) extends ConfLoader {
type T = RealSettings
type U = RealData
override def extractData(settings: RealSettings): RealData = settings.data
}
The code in processor will not compile because extractData expects input of type ConfLoader.T, but conf.settings is of type Conf.T. Those are different types.
However, I have specified that both must be subclasses of MySettings, so it should be the case I can use one where the other is desired. I understand Scala does not compile the code, but is there some workaround so that I can pass conf.settings to confLoader.extractData?
===
I want to report that for the code I wrote above, there is a way to write it that would decrease my usage of dependent types. I noticed today while experimenting with Traits that Scala supports subclassing on defs and vals on classes that implement the Trait. So I only need to create a dependent type for the argument for extractData, and not the output.
import java.util.UUID
object TestDependentTypes extends App{
val myConf = RealConf(UUID.randomUUID(), RealSettings(RealData(5, 25.0)))
RealConfLoader(7).extractData(myConf.settings)
def processor(confLoader: ConfLoader, conf: Conf) = confLoader.extractData(conf.settings.asInstanceOf[confLoader.T])
}
trait Data
case class RealData(anInt: Int, aDouble: Double) extends Data
trait MySettings
case class RealSettings(data: RealData) extends MySettings
trait Conf {
def id: UUID
def settings: MySettings
}
case class RealConf(id: UUID, settings: RealSettings) extends Conf
trait ConfLoader{
type T <: MySettings
def extractData(settings: T): Data
}
case class RealConfLoader(someInfo: Int) extends ConfLoader {
type T = RealSettings
override def extractData(settings: RealSettings): RealData = settings.data
}
The above code does the same thing and reduces dependence on dependent types. I have only removed processor from the code. For the implementation of processor, refer to any of the solutions below.
The code in processor will not compile because extractData expects input of type ConfLoader.T, but conf.settings is of type Conf.T. Those are different types.
In the method processor you should specify that these types are the same.
Use type refinements (1, 2) for that: either
def processor[_T](confLoader: ConfLoader { type T = _T }, conf: Conf { type T = _T }) =
confLoader.extractData(conf.settings)
or
def processor(confLoader: ConfLoader)(conf: Conf { type T = confLoader.T }) =
confLoader.extractData(conf.settings)
or
def processor(conf: Conf)(confLoader: ConfLoader { type T = conf.T }) =
confLoader.extractData(conf.settings)
IMHO if you don't need any of the capabilities provided by dependent types, you should just use plain type parameters.
Thus:
trait Conf[S <: MySettings] {
def id: UUID
def settings: S
}
final case class RealConf(id: UUID, settings: RealSettings) extends Conf[RealSettings]
trait ConfLoader[S <: MySettings, D <: Data] {
def extractData(settings: S): D
}
final case class RealConfLoader(someInfo: Int) extends ConfLoader[RealSettings, RealData] {
override def extractData(settings: RealSettings): RealData =
settings.data
}
def processor[S <: MySettings, D <: Data](loader: ConfLoader[S, D])(conf: Conf[S]): D =
loader.extractData(conf.settings)
But, if you really require them to be type members, you may ensure both are the same.
def processor(loader: ConfLoader)(conf: Conf)
(implicit ev: conf.S <:< loader.S): loader.D =
loader.extractData(conf.settings)
I was trying to implement a similar structure with an idea to have a common trait to work with different Input instances regardless of their InType.
trait AnyInput {
type InType
val obj : InType
}
abstract class Input[T](obj: T) extends AnyInput {
type InType = T
}
case class InpImage(image: ByteStream) extends Input[ByteStream](image)
case class InpString(text: String) extends Input[String](text)
.
.
.
trait InputProcessor[T <: Input[T#InType]] {
...
}
and I get the "cyclic reference involving type T error" in the InputProcessor definition
It is important to notice, that there might be a couple different case class implementing Input[String] or Input[ByteStream]. So writing it out as
case class StringInput(s: String) extends Input[String](s)
case class IntInput(numb: Int) extends Input[Int](numb)
is not the best workaround
Maybe you can use
trait InputProcessor[S, T <: Input[S]] {
// ...
}
you can try something like this
trait InputProcessor[S <: AnyInput, T <: Input[S#InType]] {
implicit val evidence: T =:= S = implicitly[T =:= S]
}
and than the implementation would be:
class ImageProcessor extends InputProcessor[InpImage, InpImage] { }
you can read more about =:= here: https://stackoverflow.com/a/3427759/245024
EDIT:
added an example and the implementation to the evidence
notice that when extending InputProcessor, if you pass 2 different type parameters, the code won't compile (as you would expect)
I am trying to get hold of a shapeless Generic for a case class with a marker trait, like this:
case class X(a:String)
trait UniversalTrait extends Any {}
object MyApp extends App {
val ok = Generic[X]
val notOk = Generic[X with UniversalTrait]
}
It doesn't compile, with error could not find implicit value for parameter gen: shapeless.Generic[X with UniversalTrait] in the notOk line. Why is that? And can something be done?
Side note: I thought that it might be something to do with from not being able to add the marker trait to the returned instance, so I attempted fixing things by adding this:
object UniversalTrait {
implicit def genGeneric[P1<:Product with UniversalTrait,P2<:Product,L<:HList]
(implicit constraint: P1 =:= P2 with UniversalTrait,
underlying: Generic.Aux[P2,L]): Generic.Aux[P1,L] = new Generic[P1]{
type Repr=L
def to(t: P1): Repr = underlying.to(t)
def from(r: Repr): P1 = underlying.from(r).asInstanceOf[P1]
}
}
However, the error remains.
Deriving works for algebraic data types only.
That is a (sealed) trait and case classes (objects) extending the trait.
case class X(a:String) extends UniversalTrait
sealed trait UniversalTrait extends Any {}
val ok = Generic[X]
Example code:
trait A
case class B() extends A
case class C() extends A
trait D[T]
implicit object DB extends D[B]
implicit object DC extends D[C]
def getImplicit[T: D](arg: T) = implicitly[D[T]]
val list = Seq(B(), C())
list map getImplicit
how can i get implicits without explicitly casting objects in list? maybe i can do it with HList? or perhaps macros can help me?
i tried:
case class Wrap[T](v: T)
object getImplicit extends (Wrap ~> D) {
def apply[T](arg: Wrap[T]) = implicitly[D[T]]
}
val list = Wrap(B()) :: Wrap(C()) :: HNil
list map getImplicit
and i get compilation error:
could not find implicit value for parameter e: D[T]
def apply[T](arg: Wrap[T]) = implicitly[D[T]]
You will have to supply the type class to the apply method of getImplicit. Unfortunately that means you'll have to use the long form of Poly1:
object getImplicit extends Poly1 {
implicit def default[T: D] = at[Wrap[T]](_ => implicitly[D[T]])
}
After this change, your code will compile.