Scala - how to define factory method for contravariant class? - scala

I have a trait with common parameters for a data source, with case classes for each actual source
trait AbstractSource {
val name: String
}
case class ConcreteSource(name: String) extends AbstractSource
I also have a trait for a class which acts on this data source (contravariant for the source)
trait AbstractConsumer[-T <: AbstractSource] {
def foo(inp: T): Unit
}
class ConcreteConsumer extends AbstractConsumer[ConcreteSource] {
override def foo(inp: ConcreteSource): Unit =
println(inp.name)
}
I want to create a factory method for my pipeline method which creates the correct consumer based on the input data source. I have tried the following but both have errors
object ConsumerFactory {
def create(inp: AbstractSource): AbstractConsumer[_ <: AbstractSource] =
inp match {
case _: ConcreteSource => new ConcreteConsumer()
case _ => ???
}
def createTwo[T <: AbstractSource](inp: T): AbstractConsumer[T] =
inp match {
case _: ConcreteSource => new ConcreteConsumer() // errors "required: AbstractConsumer[T], found: ConcreteConsumer"
case _ => ???
}
}
class Main {
def pipeline[T <: AbstractSource](consumer: AbstractConsumer[T], source: T): Unit =
consumer.foo(source)
def execute(): Unit = {
val consumer: ConcreteSource = ConcreteSource("john")
val source = ConsumerFactory.create(consumer) // errors "found: AbstractConsumer[_$1] where type _$1 <: AbstractSource, required: AbstractConsumer[ConcreteSource]"
val source = ConsumerFactory.createTwo(consumer)
pipeline(source, consumer)
}
}
val x = new Main()
x.execute()
If I understand correctly, the issue is that I need to supply a subtype of AbstractConsumer[T] to the pipeline, but I don't know how to do this based on the input due to the contravariant type parameter.

IMHO, theese kinds of problems are more easily solvable with a typeclass, like this:
trait AbstractConsumer[-S <: AbstractSource] {
def consume(inp: S): Unit
}
object AbstractConsumer {
sealed trait ConsumerFactory[S <: AbstractSource] {
type Consumer <: AbstractConsumer[S]
def createConsumer(): Consumer
}
type Factory[S <: AbstractSource, C <: AbstractConsumer[S]] = ConsumerFactory[S] { type Consumer = C }
object Factory {
def apply[S <: AbstractSource, C <: AbstractConsumer[S]](factory: => C): Factory[S, C] =
new ConsumerFactory[S] {
override final type Consumer = C
override final def createConsumer(): Consumer =
factory
}
}
// Get by type.
def apply[S <: AbstractSource](implicit factory: ConsumerFactory[S]): factory.Consumer =
factory.createConsumer()
// Get by value.
def fromSource[S <: AbstractSource](source: S)(implicit factory: ConsumerFactory[S]): factory.Consumer =
factory.createConsumer()
}
Then the concrete source will implement the typeclass, like this:
final class ConcreteConsumer extends AbstractConsumer[ConcreteSource] {
override def consume(inp: ConcreteSource): Unit =
println(inp.name)
}
object ConcreteConsumer {
implicit final val ConcreteConsumerFactory: AbstractConsumer.Factory[ConcreteSource, ConcreteConsumer] =
AbstractConsumer.Factory(new ConcreteConsumer())
}
And, finally, you can use it like this:
import ConcreteConsumer._ // Put the factory in scope.
val source = new ConcreteSource("john")
val consumer1 = AbstractConsumer[ConcreteSource]
val consumer2 = AbstractConsumer.fromSource(source)
You may adapt the code if the factory needs some arguments or something.
The code can be seen running here.

Related

Scala - Typeclass overriding the abstract method

I am struggling a little with scala 2.12:
I have the following hierarchy:
trait A
case class B(format: String) extends A
trait Writer {
def write(config: A): Unit
}
val writer = new Writer {
override def write(config: A) = println("hi")
}
val w = B("console")
writer.write(w)
which works fine. But I want to provide an alternate implementation for writer:
val writer = new Writer {
override def write(config: B) = println("hi")
}
But I get object creation impossible, since method write in trait Writer of type (config: Playground.A)Unit is not defined
I assumed that since B is an A, this should work. How can I override write with a config of type B where B <: A
Scastie: https://scastie.scala-lang.org/QBaiiDP4Sj2lptUjrWLJYw
EDIT: ------------------------------------------------------------
Based on some inputs, I changed the implementation to:
sealed trait A
case class B(format: String) extends A
trait Writer[+T] {
def write[S >: T](config: S): Unit
}
val writer: Writer[A] = new Writer[B] {
override def write[B](config: B) = println("hi")
}
val b = B("console")
writer.write(b)
which works.
But if I modify it to access the variables in config, it breaks:
sealed trait A
case class B(format: String) extends A
trait Writer[+T] {
def write[S >: T](config: S): Unit
}
val writer: Writer[A] = new Writer[B] {
override def write[B](config: B) = println(config.format)
}
val b = B("console")
writer.write(b)
with value format is not a member of type parameter B
https://scastie.scala-lang.org/Xj2rKbbiTmG7raZgQZYfHA
Appreciate the inputs.
You're very close with your latest version. As Matthias Berndt pointed out, the write method declares a new type parameter, but should use the one declared on the trait. In addition, the type parameter should be contravariant.
This code compiles and prints console:
sealed trait A
case class B(format: String) extends A
trait Writer[-T <: A] {
def write(config: T): Unit
}
val writer: Writer[B] = new Writer[B] {
override def write(config: B) = println(config.format)
}
val b = B("console")
writer.write(b)
Note that, because B is a subtype of A, you can also use a Writer[A] with an instance of B. Because Writer is contravariant, you can assign a value of type Writer[A] to a variable of type Writer[B]:
val aWriter: Writer[B] = new Writer[A] {
override def write(config: A) = println(s"Got A: $config")
}
aWriter.write(b) // prints "Got A: B(console)"
You can't do the opposite (assign a Writer[B] value to a Writer[A] variable) because a Writer[A] would be able to accept any value of type A, while a Writer[B] can only accept values of type B.
https://scastie.scala-lang.org/TimMoore/bd5E1p99TLCDVfMbElKqFg/8
It doesn't work because Writer declares that its write method will accept an arbitrary A. What if someone decides to pass an A that is not a B to writer.write? Then it wouldn't work, so the compiler stops you from doing that.

Import does not bring implicits in scope

I am facing an error about unreachable implicits in scope:
Error:(38, 68) could not find implicit value for parameter strategy: XXX.NeoStrategy[T]
(summoner: Summoner, v: String) => summoner.summonEvaluation[T](v)
I implement the answer of Tim to that question : https://stackoverflow.com/a/56668734/3896166
I tried to import the implicit object Strategies within TypeTable scope with :
import XXX.NeoStrategies._
but to no success.
The followings are each file of the base logic I want to use:
object TypeLib {
sealed trait Type_top
trait Type_A extends Type_top
trait Type_B extends Type_top
}
trait NeoStrategy[T <: Type_top] {
def evaluate(v: String, helper: Helper): Int
}
object NeoStrategies {
implicit object NeoStrategy_A extends NeoStrategy[Type_A] {
def evaluate(v: String, helper: Helper): Int = 1
}
implicit object NeoStrategy_B extends NeoStrategy[Type_B] {
def evaluate(v: String, helper: Helper): Int = 2
}
}
case class Helper(name: String) {
def summonEvaluation[T <: Type_top](v: String)(implicit strategy: NeoStrategy[T]): Int = {
strategy.evaluate(v, this)
}
}
trait TypeOMap {
protected def computeStuff[T <: Type_top]: (Helper, String) => Int
protected val computeMap: Map[String, (Helper, String) => Int]
}
import XXX.NeoStrategies._
trait TypeTable extends TypeOMap {
override protected def computeStuff[T <: Type_top]: (Helper, String) => Int = {
(helper: Helper, v: String) => helper.summonEvaluation[T](v)
}
override protected val computeMap = Map(
"a" -> computeStuff[Type_A],
"b" -> computeStuff[Type_B]
)
}
class Summoner extends TypeTable {
def callsMapAndEvaluates(typeIdentifier: String, helper: Helper, param: String): Double = {
computeMap(typeIdentifier)(helper, param)
}
}
object StackO {
def main(args: Array[String]): Unit = {
val mySummoner = new Summoner
// mySummoner allows the selecting of a given type with
// its "typeIdentifier" input in combination with the "TypeTable" it extends
val r = mySummoner.callsMapAndEvaluates("a", Helper("make it right"), "I, parameter")
}
}
This is not the first time I use implicits but not with something like the computeMap above. Still, I understand the logic of it, but fail at making it right.
How can I have summoner.summonEvaluation[T](v) find the required implicit?
Just add context bound
override protected def computeStuff[T <: Type_top : NeoStrategy] ...
It seems you want to work with singleton types. In Scala 2.12 + Shapeless
import shapeless.Witness
object TypeLib {
sealed trait Type_top
trait Type_A extends Type_top
trait Type_B extends Type_top
}
import TypeLib._
trait NeoStrategy[S <: String] {
type T <: Type_top
def evaluate(v: S, summoner: Summoner): Int
}
object NeoStrategy {
type Aux[S <: String, T0 <: Type_top] = NeoStrategy[S] { type T = T0 }
def mkStrategy[S <: String, T0 <: Type_top](f: (S, Summoner) => Int): Aux[S, T0] = new NeoStrategy[S] {
override type T = T0
override def evaluate(v: S, summoner: Summoner): Int = f(v, summoner)
}
implicit val NeoStrategy_A: NeoStrategy.Aux[Witness.`"a"`.T, Type_A] = mkStrategy((_, _) => 1)
implicit val NeoStrategy_B: NeoStrategy.Aux[Witness.`"b"`.T, Type_B] = mkStrategy((_, _) => 2)
}
case class Summoner(name: String) {
def summonEvaluation[S <: String](s: Witness.Aux[S])(implicit
strategy: NeoStrategy[S]): Int = {
strategy.evaluate(s.value, this)
}
}
def main(args: Array[String]): Unit = {
val mySummoner = Summoner("stack question")
val r = mySummoner.summonEvaluation("a")
val r1 = mySummoner.summonEvaluation("b")
println(r) // 1
println(r1) // 2
}
In Scala 2.13
object TypeLib {
sealed trait Type_top
trait Type_A extends Type_top
trait Type_B extends Type_top
}
import TypeLib._
trait NeoStrategy[S <: String with Singleton] {
type T <: Type_top
def evaluate(v: S, summoner: Summoner): Int
}
object NeoStrategy {
type Aux[S <: String with Singleton, T0 <: Type_top] = NeoStrategy[S] { type T = T0 }
def mkStrategy[S <: String with Singleton, T0 <: Type_top](f: (S, Summoner) => Int): Aux[S, T0] = new NeoStrategy[S] {
override type T = T0
override def evaluate(v: S, summoner: Summoner): Int = f(v, summoner)
}
implicit val NeoStrategy_A: NeoStrategy.Aux["a", Type_A] = mkStrategy((_, _) => 1)
implicit val NeoStrategy_B: NeoStrategy.Aux["b", Type_B] = mkStrategy((_, _) => 2)
}
case class Summoner(name: String) {
def summonEvaluation[S <: String with Singleton](s: S)(implicit
value: ValueOf[S],
strategy: NeoStrategy[S]): Int = {
strategy.evaluate(s, this)
}
}
def main(args: Array[String]): Unit = {
val mySummoner = Summoner("stack question")
val r = mySummoner.summonEvaluation("a")
val r1 = mySummoner.summonEvaluation("b")
println(r) // 1
println(r1) // 2
}
The underlying problem is this:
override protected def computeStuff[T <: Type_top]: (Helper, String) => Int = {
(helper: Helper, v: String) => helper.summonEvaluation[T](v) // implicit for NeoStrategy[T]...?
}
Since summonEvaluation[T] requires an implicit argument of type NeoStrategy[T], this means you must have one in scope for any T that's a subclass of Type_top. However, NeoStrategies only provides two instances: one for Type_A and Type_B. This is not enough for the compiler. Understandably so - for instance, you haven't provided any NeoStrategy for
Type_top itself
subclasses of Type_A and Type_B (perfectly legal to create)
There are two basic ways you can handle this:
Delaying the implicit resolution
As per the other answer, instead of trying to resolve the implicit inside computeStuff, add a context bound there too. If the point where you have to supply the implicit is only reached when you know what T is, you won't have to provide instances for any possible subtype.
Providing implicits for all possible subtypes
If absolutely you want to keep the implicit resolution inside computeStuff, you're going to have to offer a method
implicit def getNeoStrategy[T <: Type_top] : NeoStrategy[T] = ???
Unfortunately, doing this is probably going to involve a bunch of reflection and potentially runtime errors for edge cases, so I'd recommend the context bound on computeStuff.

Scala type class to extend generic type: No implicits found for parameter

I want to write a type class, to add some behavior to a generic type. However, I cannot figure out how to do it; I keep running into the error below.
Imagine you have a generic type MyList[A]:
trait MyList[A]
object MyList {
case class Empty[A]() extends MyList[A]
case class Node[A](value: A, next: MyList[A]) extends MyList[A]
}
Now you want to add some behavior to this class, e.g. to convert it into a Stream[A]. A type class based extension would seem appropriate:
// inspired by https://scalac.io/typeclasses-in-scala
trait MyListExt[T, A <: MyList[T]] {
def stream(a: A): Stream[T]
}
object MyListExt {
def apply[T, A <: MyList[T]](implicit a: MyListExt[T, A]): MyListExt[T, A] = a
object ops {
implicit class MyListExtOps[T, A <: MyList[T]](val a: A) extends AnyVal {
def stream(implicit ext: MyListExt[T, A]): Stream[T] = ext.stream(a)
}
}
private type T0
implicit val myListToStreamImpl: MyListExt[T0, MyList[T0]] = new MyListExt[T0, MyList[T0]] {
override def stream(a: MyList[T0]): Stream[T0] = {
def fold[T1](l: MyList[T1], acc: Stream[T1]): Stream[T1] = l match {
case MyList.Empty() => acc
case MyList.Node(value, next) => fold(next, acc :+ value)
}
fold(a, Stream.empty)
}
}
}
When I now try to use this type class in my code, I get the following error at l.stream:
No implicits found for parameter ext: MyListExt[T_, MyList[Int]]
object MyListTest {
def main(args: Array[String]): Unit = {
import MyListExt.ops._
val l: MyList[Int] = MyList.Node(1, MyList.Node(2, MyList.Node(3, MyList.Empty())))
l.stream.foreach(println)
}
}
What am I doing wrong, or how can I get my l.stream to work?
I have seen many examples involving type classes and implicit conversion, but none so far operating on generic types.
implicit def myListToStreamImpl[T]: MyListExt[T, MyList[T]] = new MyListExt[T, MyList[T]] {
override def stream(a: MyList[T]): Stream[T] = {
def fold(l: MyList[T1], acc: Stream[T1]): Stream[T1] = l match {
case MyList.Empty() => acc
case MyList.Node(value, next) => fold(next, acc :+ value)
}
fold(a, Stream.empty[T1])
}
}
Your types don't align because you've used that private type for whatever bizarre reason. Types nested inside objects have a completely different application, and they don't relate to your current use case.
The trouble is that in l.stream.foreach(println) the l is implicitly transformed to new MyListExt.ops.MyListExtOps[.., ..](l) and generics are inferred to be [Nothing, MyList[Int]], which doesn't satisfy [T, A <: MyList[T]].
I can't see reason to parametrize MyListExt with both T and A <: MyList[T]. I guess T is enough, use MyList[T] instead of A.
Don't use private type T0, just parametrize myListToStreamImpl (make it def) with T0 aka T.
Try
trait MyList[A]
object MyList {
case class Empty[A]() extends MyList[A]
case class Node[A](value: A, next: MyList[A]) extends MyList[A]
}
trait MyListExt[T] {
def stream(a: MyList[T]): Stream[T]
}
object MyListExt {
def apply[T](implicit a: MyListExt[T]): MyListExt[T] = a
object ops {
implicit class MyListExtOps[T](val a: MyList[T]) extends AnyVal {
def stream(implicit ext: MyListExt[T]): Stream[T] = ext.stream(a)
}
}
implicit def myListToStreamImpl[T]: MyListExt[T] = new MyListExt[T] {
override def stream(a: MyList[T]): Stream[T] = {
def fold[T1](l: MyList[T1], acc: Stream[T1]): Stream[T1] = l match {
case MyList.Empty() => acc
case MyList.Node(value, next) => fold(next, acc :+ value)
}
fold(a, Stream.empty)
}
}
}
object MyListTest {
def main(args: Array[String]): Unit = {
import MyListExt.ops._
val l: MyList[Int] = MyList.Node(1, MyList.Node(2, MyList.Node(3, MyList.Empty())))
l.stream.foreach(println)
}
}

Get an implicit instance by class name

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.

Provide implicits for all subtypes of sealed type

In my application I have multiple case classes and objects which are part of sealed trait hierarchy. I use them as messages in Akka.
Those classes need to be converted to user friendly form before sending through websocket.
Previously I used big pattern match to convert them in single place, but as number of types grows I would like to use implicit conversion:
object Types {
sealed trait Type
case object SubType1 extends Type
case object SubType2 extends Type
case object SubType3 extends Type
trait Converter[T] {
def convert(t: T): Int
}
}
object Implicits {
import Types._
implicit object Type1Coverter extends Converter[SubType1.type] {
override def convert(t: SubType1.type): Int = 1
}
implicit object Type2Coverter extends Converter[SubType2.type] {
override def convert(t: SubType2.type): Int = 2
}
implicit object Type3Coverter extends Converter[SubType3.type] {
override def convert(t: SubType3.type): Int = 3
}
}
object Conversion {
import Types._
def convert[T: Converter](t: T): Int = {
implicitly[Converter[T]].convert(t)
}
def convert2[T <: Type](t: T)(implicit ev1: Converter[SubType1.type], ev2: Converter[SubType2.type], ev3: Converter[SubType3.type]): Int = {
t match {
case t1#SubType1 =>
implicitly[Converter[SubType1.type]].convert(t1)
case t2#SubType2 =>
implicitly[Converter[SubType2.type]].convert(t2)
case t3#SubType3 =>
implicitly[Converter[SubType3.type]].convert(t3)
}
}
}
I would like to use them as follow:
import Types._
import Conversion._
import Implicits._
val t1 = SubType1
val x1: Int = convert(t1)
val t: Type = SubType2 // T is of type Type
//Is it possible to handle that?
//val x: Int = convert(t)
val y: Int = convert2(t)
I would love to know if there is any "magic" way to generate something like convert2 automatically without writing a macro. Maybe there is already a library which provides macro like this?
Since you have no info at compile time about t's type, you have to work at runtime.
if you put your Converters in a sealed family, you could do something like the follwing, using a technique explained in this question:
import shapeless._
trait AllSingletons[A, C <: Coproduct] {
def values: List[A]
}
object AllSingletons {
implicit def cnilSingletons[A]: AllSingletons[A, CNil] =
new AllSingletons[A, CNil] {
def values = Nil
}
implicit def coproductSingletons[A, H <: A, T <: Coproduct](implicit
tsc: AllSingletons[A, T],
witness: Witness.Aux[H]): AllSingletons[A, H :+: T] =
new AllSingletons[A, H :+: T] {
def values = witness.value :: tsc.values
}
}
trait EnumerableAdt[A] {
def values: Set[A]
}
object EnumerableAdt {
implicit def fromAllSingletons[A, C <: Coproduct](implicit
gen: Generic.Aux[A, C],
singletons: AllSingletons[A, C]): EnumerableAdt[A] =
new EnumerableAdt[A] {
def values = singletons.values.toSet
}
}
object Types {
sealed trait Type
case object SubType1 extends Type
case object SubType2 extends Type
case object SubType3 extends Type
sealed abstract class Converter[T <: Type: ClassTag] {
def convert(t: T): Int
def convertibleObjectClass = implicitly[ClassTag[T]].runtimeClass
}
object Implicits {
implicit object Type1Converter extends Converter[SubType1.type] {
override def convert(t: SubType1.type): Int = 1
}
implicit object Type2Converter extends Converter[SubType2.type] {
override def convert(t: SubType2.type): Int = 2
}
// let's pretend you FORGOT to add Type3Converter
// implicit object Type3Converter extends Converter[SubType3.type] {
// override def convert(t: SubType3.type): Int = 3
// }
}
}
object Conversion {
import Types._
val AllConverters: Map[Class[_], Converter[_ <: Type]] = implicitly[EnumerableAdt[Converter[_ <: Type]]].values
.map(c => c.convertibleObjectClass -> c).toMap
// You're sure you have all the converters here but you can't be sure you remembered to add one per subtype... you have to test it
// you are sure this cast doesn't fail anyway because of how you created the map
def findConverter[T <: Type](t: T) = AllConverters.get(t.getClass).asInstanceOf[Option[Converter[T]]]
def convert2[T <: Type](t: T): Option[Int] = findConverter(t).map(_.convert(t))
}
object Test extends App {
import Types._
import Conversion._
val t: Type = SubType2
val t2: Type = SubType3
// works, because a Converter[Subtype2.type] exists
val a: Option[Int] = convert2(t)
// returns None, because a Converter[Subtype3.type] doesn't exist
val b: Option[Int] = convert2(t2)
}