Ad-hoc polymorphism for reflection created case classes Scala - scala

I need to implement Ad-hoc polymorphism, consider this code:
trait BlockInputRequest
case class StaticBlockInput(
content: String
) extends BlockInputRequest
case class StaticBlockOutput(
content: String = ""
)
trait BlockProcessor[T] {
def processBlock(request: T, project: String, userEmail: String, empty: Boolean = false)(implicit ec: ExecutionContext): Future[Any]
}
implicit val StaticBlockInputProcessor: BlockProcessor[StaticBlockInput] = new BlockProcessor[StaticBlockInput] {
override def processBlock(request: StaticBlockInput, project: String, userEmail: String, empty: Boolean)(implicit ec: ExecutionContext): Future[Any] = {
Future.successful(
if (empty)
StaticBlockOutput()
else
StaticBlockOutput(request.content)
)
}
}
implicit class BlockProcessorOps[T](request: T)(implicit ev: BlockProcessor[T]) {
def processBlock(project: String, userEmail: String, empty: Boolean): Future[Any] = ev.processBlock(request, project, userEmail, empty)
}
Then I have no problems to run something like:
StaticBlockInput("test string").processBlock("myProject","user#example.com",false)
But what if my input was created by reflection from some other part of code and actual class type is erased and all I have is an instance of generic type and manifest:
val manifest: Manifest[I <: BlockInputRequest] = ... // type is saved
val block: BlockInputRequest = ... // created using reflection
block.processBlock("myProject","user#example.com",false)
Is there a way I can resolve BlockProcessor? Or maybe I can use reflection again in some way?

Related

How to restrict a method only to being used with a specific type?

Suppose I have a case class below
case class SomeCaseClass[M] private (
value: String
)
and in another file, I have the following trait and object.
trait SomeTrait[A] {
def get(oldId: String): A
:
}
object SomeObject {
private[this] def init[A](): SomeTrait[A] = new SomeTrait[A] {
def get(oldId: String): A = id(oldId)
:
}
val aaa: SomeTrait[String] = init[String]()
val bbb: SomeTrait[SomeCaseClass[String]] = init[SomeCaseClass[String]]()
}
How should I modify the code so that restrict the init method only to being used with SomeCaseClass[_] type and not with any types like String as above?
Ideally with some modification to the code, the line val aaa: SomeTrait[String] = init[String]() should cause compilation error.
This is what I came up with:
case class SomeCaseClass[M] private (
value: String
)
trait SomeTrait[A] {
def get(oldId: String): A
}
private[this] def init[A <: SomeCaseClass[_]](): SomeTrait[A] = new SomeTrait[A] {
def get(oldId: String): A = ???
}
val aaa: SomeTrait[String] = init[String]() // Will fail
val bbb: SomeTrait[SomeCaseClass[String]] = init[SomeCaseClass[String]]()
It fails with
ScalaFiddle.scala:16: error: type arguments [String] do not conform to method init's type parameter bounds [A <: ScalaFiddle.this.SomeCaseClass[_$1] forSome { type _$1 }]
You can check this scalafiddle.
I do not know if this is the best approach, but init[A <: SomeCaseClass[_]] is adding a type bound to A, and forcing A to be a Subclass of SomeCaseClass. I would love to know if there is a better way though.
You can force a type parameter to be equal to some type B by using an implicit parameter:
def foo[A](implicit e: A =:= B): …
Also see this question.
To add some more value to this answer.
Following code shows how to use the implicit parameter e: A =:= String to convert an A to a String.
def bar(b: String): Unit = println(b)
def foo[A](a: A)(implicit e: A =:= String): Unit = {
bar(e(a))
}
foo("hi") //compiles
foo(5) //error: Cannot prove that scala.this.Int =:= String.
Answer to problem the OP has
This problem is much simpler: Make the method parametric only in the parameter A of SomeCaseClass[A], instead of using the whole type SomeCaseClass[A] as a type parameter:
private[this] def init[A](): SomeTrait[SomeCaseClass[A]] = new
SomeTrait[SomeCaseClass[A]] {
def get(oldId: String): SomeCaseClass[A] = ???
}
This is based on the answer above:
case class SomeCaseClass[M] private (
value: String
)
trait SomeTrait[A] {
def get(oldId: String): SomeCaseClass[A]
}
private[this] def init[A](): SomeTrait[A] = new SomeTrait[A] {
def get(oldId: String): SomeCaseClass[A] = ???
}
val aaa: SomeTrait[String] = init[String]()
(https://scalafiddle.io/sf/KuXZc0h/3)
This doesn't allow other types than SomeCaseClass to be used with SomeTrait.

How to work with abstract type members in Scala

I'm running into issues with the following code (heavily simplified). Looks like the problem may be with the way I use abstract type members. I would appreciate someone pointing out and explaining what I'm doing wrong here. Compiler error at the bottom.
I'm using Scala version 2.12.
trait DataType {
type A
def convert(value: String): A
def convertToString(value: A): String
}
case object IntType extends DataType {
type A = Int
def convert(value: String): A = value.toInt
def convertToString(value: A): String = value.toString
}
trait Codec[T <: DataType] {
val dtype: T
def encode(data: Array[String]): Array[T#A]
def decode(data: Array[T#A]): Array[String]
}
class CodecImp[T <: DataType](val dtype: T)(implicit tag: ClassTag[T#A]) extends Codec[T] {
def encode(data: Array[String]): Array[T#A] = {
Array[T#A](dtype.convert(data(0)))
}
def decode(data: Array[T#A]): Array[String] = {
Array[String](dtype.convertToString(data(0)))
}
}
val cod = new CodecImp(IntType)
val encoded = cod.encode(Array("1", "2", "3")) // expecting: Array[IntType.A]
val decoded = cod.decode(encoded) // expecting: Array[String]
Compiler error.
Error:(30, 50) type mismatch;
found : T#A
required: CodecImp.this.dtype.A
Array[String](dtype.convertToString(data(0)))
^
I found What does the # operator mean in Scala? explained the '#' operator pretty well.
Each instance of DataType has it's own path dependent type A.
The difference between: T#A meaning A is a nested class of any T and dtype.A meaning the A class of dtype
You could change the Codec trait method signatures to something like:
def encode(data: Array[String]): Array[dtype.A]
def decode(data: Array[dtype.A]): Array[String]
But type parameters might be a better way to express the relation.
This is caused by dtype.convertToString(data(0)) this method is wanting a variable with type: dtype#A, this type is decided by the variable dtype, but data type is Array[T#A], so this caused type mismatch, it's can't resolve in Scala, Since we can't state our method, like: def decode(data: Array[dType.A])... that's compiler expected.
And You can solve this by generics type agains type alias, like:
trait DataType[T] {
def convert(value: String): T
def convertToString(value: T): String
}
case object IntType extends DataType[Int] {
def convert(value: String): Int = value.toInt
def convertToString(value: Int): String = value.toString
}
class CodecImp[B](val dtype: DataType[B])(implicit tag: ClassTag[B]) {
def encode(data: Array[String]): Array[B] = {
Array[B](dtype.convert(data(0)))
}
def decode(data: Array[B]): Array[String] = {
Array[String](dtype.convertToString(data(0)))
}
}
The thing is that each instance of DataType can have A defined as anything whatsoever. Consider this:
class Foo extends DataType {
type A = Int
def convertToString(i: Int) = i.toString
def convert(s: String) = s.toInt
}
class Bar extends DataType {
type A = String
def convertToString(s: String) = s
def convert(s: String) = s
}
Now, if I do val codecs = Seq(CodecImpl(new Foo, new Bar)
and if that compiles, then what type should the argument be to codecs.map(_.decode(whateverMakesSenseHere))?
This doesn't work ... You can't use T#A like this, because it is abstract.
I get a feeling, you'd be better off modeling what you need to model with type parameters rather than path dependent types. This just doesn't really seem like a use case for the latter.

Scala implicit converters

I'm trying to figure out how to create an implicit converter for a particular type. In my case, that would be a Set[IdParam[T]] to a Set[IdTag[T]], where
import shapeless.tag.##
case class IdParam[T](value: IdTag[T])
type IdTag[T] = Id ## T
class Id(val value: Long)
object Id {
def tag[T](l: Long) = shapeless.tag[T][Id](new Id(l))
def value[T](l: Long) = Id.tag[T](l)
}
I wrote a simple
implicit def toIds[T](idParams: Set[IdParam[T]]): Set[IdTag[T]] = idParams.map(_.value)
which works OK. But my main question now is if there is a way to create an implicit converter which would cover both Seq and Set. Going up the hierarchy, that would mean an Iterable.
Tried the following
implicit def toIds[I <: Iterable[IdParam[T]], T](idParams: I): Iterable[IdTag[T]] = idParams.map(_.value)
The compiler refuses to accept this converter where it's needed.
[error] found : Set[tags.IdParam[tags.ProfileIdTag]]
[error] required: Set[tags.ProfileId]
[error] (which expands to) Set[model.Id with shapeless.tag.Tagged[tags.ProfileIdTag]]
EDIT
That implicit converter should be used in the Controller endpoint.
GET /campaigns #dummy.Campaigns.all(profileId: Set[IdParam[ProfileIdTag]] ?= Set.empty)
I have a QueryStringBindable which converts the query param retrieved as a string into a Set[IdParam[A]]
object IdQueryStringBinder {
implicit def idParamQueryStringBinder[A](implicit stringBinder: QueryStringBindable[String]) =
new QueryStringBindable[IdParam[A]] {
def bind(key: String, params: Map[String, Seq[String]]): Option[Either[String, IdParam[A]]] =
for {
idEither <- stringBinder.bind(key, params)
} yield {
idEither match {
case Right(idString) =>
IdBinder.parseIdString(idString)
case Left(_) => Left("Unable to bind an Id")
}
}
override def unbind(key: String, id: IdParam[A]): String =
stringBinder.unbind(key, id.value.toString)
}
implicit def idsParamQueryStringBinder[A](implicit stringBinder: QueryStringBindable[String]) =
new QueryStringBindable[Set[IdParam[A]]] {
override def bind(key: String, params: Map[String, Seq[String]]): Option[Either[String, Set[IdParam[A]]]] = {
stringBinder.bind(key, params).map(_.right.flatMap(parse))
}
private def parse(idsString: String): Either[String, Set[IdParam[A]]] = {
val (wrongIds, correctIds) = idsString.split(",")
.map(id => IdBinder.parseIdString[A](id))
.partition(_.isLeft)
if (wrongIds.nonEmpty) {
Left(s"Could not bind the following Ids: ${wrongIds.map(_.left.get).mkString(",")}")
} else {
Right(correctIds.map(_.right.get).toSet)
}
}
override def unbind(key: String, ids: Set[IdParam[A]]): String =
stringBinder.unbind(key, ids.map(_.value.toString).mkString(","))
}
}
My Controller is
class Campaigns extends play.api.mvc.Controller {
def allByProfileId(profile: ProfileId) = ...
def all(profileIds: Set[ProfileId]) = ...
}
The first endpoint works, which uses the defined idParamQueryStringBinder with the following implicit converter
implicit def toId[T](idParam: IdParam[T]): IdTag[T] = idParam.value
You must have done some coding mistake because it works perfectly fine for me:
https://gist.github.com/kpbochenek/ce2a783d59a7bd28585e4cbf7a64cad4
next time paste full code that causes the issue not only small parts.

Scala: implicit lookup of type class instance for path-dependent type

trait Encoder[From, To] {
def encode(x: From): To
}
object Encoder {
implicit val thingToString: Encoder[Thing, String] = new Encoder[Thing, String] {
def encode(x: Thing): String = x.toString
}
}
trait Config {
type Repr
}
class MyConfig extends Config { type Repr = String }
//class ConcreteConfig { type Repr = String }
class Api[T](val config: Config) {
def doSomething(value: T)(implicit encoder: Encoder[T, config.Repr]): Unit = {}
}
case class Thing(a: Int)
object Test extends App {
import Encoder._
val api = new Api[Thing](new MyConfig)
api.doSomething(Thing(42))
}
The call to api.doSomething fails to compile:
could not find implicit value for parameter encoder: Encoder[Thing,Test.api.config.Repr]
If I change the signature of class Api[T]'s constructor so that it takes a ConcreteConfig, then the compiler can tell that config.Repr == String and the implicit lookup succeeds. But this wouldn't really work for my use case.
Is there any other way to guide the implicit lookup? Am I losing type info because I'm missing a type refinement or something?
This can't be achieved since config.Repr is not a stable path. The compiler can't determine that config.Repr = String, even though the runtime value of config is of type MyConfig.
This is going to work only if you can provide concrete config instance as a type parameter in Api, which will tell compiler what is the exact type of Repr:
class Api[T, C <: Config](val config: C) {
def doSomething(value: T)(implicit encoder: Encoder[T, config.Repr]): Unit = {}
}
object Test extends App {
import Encoder._
val api = new Api[Thing, MyConfig](new MyConfig)
api.doSomething(Thing(42))
}
Infer types one step at a time. Also, I don't see any reason for using value-dependent types here (or, for that matter, anywhere; that's a different question though).
trait Encoder[From, To] {
def encode(x: From): To
}
object Encoder {
implicit val thingToString: Encoder[Thing, String] = new Encoder[Thing, String] {
def encode(x: Thing): String = x.toString
}
}
trait Config {
type Repr
}
class MyConfig extends Config { type Repr = String }
// class ConcreteConfig { type Repr = String }
case class Api[T, C <: Config](val config: C) {
def doSomething(value: T)(implicit encoder: Encoder[T, C#Repr]): Unit = ()
}
case class ApiFor[T]() {
def withConfig[C <: Config](config: C): Api[T,C] = Api(config)
}
case class Thing(a: Int)
object Test extends App {
import Encoder._
val api = ApiFor[Thing] withConfig new MyConfig
// compiles!
api.doSomething(Thing(42))
}

Implicit conversion function to trait with a single method

Scala 2.11.4
I have the following trait
trait MyTrait{
def met(msg: String): Unit
}
and class
class MyClass{
def ac(mt: MyTrait) = {
//do some job
}
}
Now, I want to invoke ac as follows:
val myClass = new MyClass
myClass.as((msg: String) => println(msg)) //meaning that just print out Strings to stdout
So, I tried to add implicit conversion to MyTrait:
trait MyTrait {
def met(msgString: String): Unit
implicit def function2MyTrait(f: String => Unit): MyTrait = new MyTraitImpl(f)
private[this] class MyTraitImpl(f: String => Unit) extends MyTrait{
override def met(msgString: String): Unit = f(msgString)
}
}
but it refuses to compile:
Error:(16, 89) type mismatch;
found : String => Unit
required: com.test.trace.MyTrait
I came from Java 8. Is there a way to do such a thing in Scala?
function2MyTrait needs to live in the companion object:
trait MyTrait {
def met(msgString: String): Unit
}
object MyTrait {
implicit def function2MyTrait(f: String => Unit): MyTrait = new MyTraitImpl(f)
private[this] class MyTraitImpl(f: String => Unit) extends MyTrait{
override def met(msgString: String): Unit = f(msgString)
}
}
This will be no longer be necessary in Scala 2.12, as it'll allow using lambdas to implement MyTrait without going through String => Unit.