Scala, override method on generic type - scala

I am trying to build a DSL, one of the method on this DSL is parameterless and use a bounded generic type. Today I have to add a "feature" that will ideally use the same method name. However, because the only parameter is the generic one, I cannot override it with the usual way.
Is there a trick to allow the use of the same method for different generic types ?
My method looks like:
def ask[H <: Handler] = {
new CommandBuilder[H]
}
class CommandBuilder[H <: Handler] {
def toExecute[C <: H#C](command: C) = {
//...
}
}
And I would like to add:
def ask[S <: State] = {
new QueryBuilder[S]
}
class QueryBuilder[S <: State] {
def toExecute[Q <: S#Q](query: Q) = {
//...
}
}
I was thinking to pattern match a ClassTag on the type but I need strong type safety:
Query on a Handler, is not allowed. ask[State] must return QueryBuilder
Command and Query are the only supported types. The generic type of ask can only be a Handler or a State.

Maybe you could refactor your code to something like this?
sealed trait FooBar
sealed trait Foo extends FooBar {
def process(i: Int): Int
}
object Foo {
implicit final case object FooImpl extends Foo {
override def process(i: Int): Int = i + 1
}
}
sealed trait Bar extends FooBar {
def process(s: String): String
}
object Bar {
implicit final case object BarImpl extends Bar {
override def process(s: String): String = s.toUpperCase
}
}
object Test {
trait FooBarPartiallyApplied[FB <: FooBar] {
type Out
def out: Out
}
object FooBarPartiallyApplied {
type Aux[FB <: FooBar, _Out] = FooBarPartiallyApplied[FB] { type Out = _Out }
implicit final def FooPartiallyAppliedBuilder[F <: Foo]: Aux[F, FooPartiallyApplied[F]] =
new FooBarPartiallyApplied[F] {
override final type Out = FooPartiallyApplied[F]
override final val out: FooPartiallyApplied[F] =
new FooPartiallyApplied[F](dummy = true)
}
implicit final def BarPartiallyAppliedBuilder[B <: Bar]: Aux[B, BarPartiallyApplied[B]] =
new FooBarPartiallyApplied[B] {
override final type Out = BarPartiallyApplied[B]
override final val out: BarPartiallyApplied[B] =
new BarPartiallyApplied[B](dummy = true)
}
final class FooPartiallyApplied[F <: Foo](private val dummy: Boolean) extends AnyVal {
def toExecute(i: Int)(implicit foo: F): Int = foo.process(i)
}
final class BarPartiallyApplied[B <: Bar](private val dummy: Boolean) extends AnyVal {
def toExecute(s: String)(implicit bar: B): String = bar.process(s)
}
}
def ask[FB <: FooBar](implicit pa: FooBarPartiallyApplied[FB]): pa.Out =
pa.out
}
It works as expected:
Test.ask[Foo.FooImpl.type].toExecute(10)
// res: Int = 11
Test.ask[Foo.FooImpl.type].toExecute("blah")
// Type error.
Test.ask[Bar.BarImpl.type].toExecute(10)
// Type error.
Test.ask[Bar.BarImpl.type].toExecute("blah")
// res: String = "BLAH"

Related

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.

Internal type U dependent on trait def

I have a custom type, Value:
trait Value
object Value {
case class BooleanValue(record: Boolean) extends Value
case class LongValue(record: Long) extends Value
}
And a trait that knows how to get a Value, called GetsValue, given some input type T:
sealed trait GetsValue[T] { def apply(record: T): Option[Value] }
object GetsValue {
trait GetsBooleanValue[T] extends GetsValue[T] { override def apply(record: T): Option[Value.BooleanValue] }
trait GetsLongValue[T] extends GetsValue[T] { override def apply(record: T): Option[Value.LongValue] }
}
Notice that GetsValue is sealed, so users will only extend GetsValue.GetsBooleanValue or GetsValue.GetsLongValue.
trait Extractor[T] {
def title: String
def getsValue: GetsValue[T]
def relatedValue[U]: U = ??? // question below
}
What I want to achieve is the following:
If getsValue is a GetsValue.GetsBooleanValue[_], then return a String with the text "boo!" (i.e., U is of type String).
If getsValue is a GetsValue.GetsLongValue[_], then return a Double with the value of 1.1 (i.e., U is of type Double).
Also note that I don't want to match on getsValue's type T. I want to match irrespective of what its type T is.
I want to use type class / implicits if that makes sense. Using Either is not an option for me.
Perhaps something like this would work:
First, modify GetsValue to add a type parameter that specifies the return type:
sealed trait GetsValue[T, V <: Value] { def apply(record: T): Option[V] }
object GetsValue {
trait GetsBooleanValue[T] extends GetsValue[T, Value.BooleanValue] { }
trait GetsLongValue[T] extends GetsValue[T, Value.LongValue] { }
}
Then a trait to correlate a type V to a value of U:
trait RelatedValue[V <: Value, U] {
def get: U
}
And some implicit values of that trait:
object Extractor {
implicit val boolRV = new RelatedValue[Value.BooleanValue, String] { def get = "boo!" }
implicit val longRV = new RelatedValue[Value.LongValue, Double] { def get = 1.1 }
}
Then your Extractor trait can be:
trait Extractor[T] {
type V <: Value
type U
def title: String
def getsValue: GetsValue[T, V]
def relatedValue(implicit rv: RelatedValue[V, U]): U = rv.get
}
An example implementation:
object Example extends Extractor[String] {
type V = Value.BooleanValue
type U = String
def title = "Example"
def getsValue = new GetsValue.GetsBooleanValue[String] {
def apply(s: String) = None
}
}
import Extractor._
println(Example.relatedValue)
Prints "boo!"

How to make method return type covariant

I have a following classes:
trait Foo {
def update: Foo
}
class ConcreteFoo extends Foo {
override def update: Foo = new ConcreteFoo
}
class FooManager[T <: Foo](val foos: mutable.Map[String, T]) {
def update(id: String): Unit = {
foos.update(id, foos(id).update)
}
}
And of course update function does not compiles:
Type missmatch found Foo required T
How to make def update: Foo covariant?
Looks like you want something like F-bounded polymorphism:
trait Foo[T <: Foo[T]] { self: T =>
def update: T
}
class ConcreteFoo extends Foo[ConcreteFoo] {
override def update = new ConcreteFoo
}
class FooManager[T <: Foo[T]](val foos: mutable.Map[String, T]) {
def update(id: String): Unit = {
foos.update(id, foos(id).update)
}
}
An alternative, and probably simpler, solution is to use an immutable Map, as Luka said. But then there's no need to have type parameters anymore:
trait Foo {
def update: Foo
}
class ConcreteFoo extends Foo {
override def update: Foo = new ConcreteFoo
}
class FooManager(private var _foos: immutable.Map[String, Foo]) {
def foos = _foos
def update(id: String): Unit = {
_foos = _foos.updated(id, _foos(id).update)
}
}
You could also keep your current solution and remove the type parameter. But then you have the slight inconvenience that you can't pass a mutable.Map[String,ConcreteFoo] to the constructor of FooManager.
I'd suggest going with an immutable Map instead. As only immutable collections can have covariant type parameters.
class FooManager[+T <: Foo](val foos: immutable.Map[String, T]) {
def update(id: String): FooManager[Foo] = {
new FooManager(foos.updated(id, foos(id).update))
}
}

How do I encode this method with an implicit parameter group which contains a dependent type?

Given a typeclass Printer with a dependent type Show[A]:
trait Printer {
type Show[A]
def show[A](x: A)(implicit z: Show[A]): String
}
object Printer {
// the intent here is this is the dumb fallback
// and a user can have a better alternative in scope
implicit val dumbPrinter: Printer = new Printer {
type Show[A] = DummyImplicit
def show[A](x: A)(implicit z: DummyImplicit): String = x.toString
}
}
How do I encode this method:
def r[A](x: A)(implicit printer: Printer, show: printer.Show[A]): String =
printer.show(x)(show)
I've been trying to adapt the working code in #MilesSabin's gist https://gist.github.com/milessabin/cadd73b7756fe4097ca0 and #TravisBrown's blog post https://meta.plasm.us/posts/2015/07/11/roll-your-own-scala/, but I can't find an encoding that works.
You can force type inference one step at a time by introducing intermediate contexts:
object example {
trait AnyPrinter {
type Show <: AnyShow
}
trait AnyShow {
type X
def apply(x: X): String
}
def print[P <: AnyPrinter](implicit p: P): print[P] = new print[P]
class print[P <: AnyPrinter] {
def it[E](e: E)(implicit s: P#Show { type X = E }): String = s(e)
}
// the intent here is this is the dumb fallback
// and a user can have a better alternative in scope
implicit object DumbPrinter extends AnyPrinter {
type Show = AnyDumbShow
}
trait AnyDumbShow extends AnyShow {
def apply(x: X): String = x.toString
}
case class DumbShow[Z]() extends AnyDumbShow { type X = Z }
implicit def dumbShow[Z]:DumbShow[Z] = DumbShow()
val buh: String = print.it(2)
}

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)
}