I want to build a function that takes as input a generic function with one argument,
than parse the argument based on type and call the input function:
class PatternMatching {
val a = "test"
def test[T: TypeTag](callback: T => Unit): Unit = {
callback match {
case x if typeOf[T] <:< typeOf[String] => callback(a)
case x if typeOf[T] <:< typeOf[Array[Char]] => callback(a.toCharArray)
case _ => throw new IllegalArgumentException("error")
}
}
}
I see that type is correctly inferred but is not possible to invoke the function:
type mismatch;
found : PatternMatching.this.a.type (with underlying type String)
required: T
case x if typeOf[T] <:< typeOf[String] => callback(a)
I understand that it's expecting a type, but I can't find a way out.
You need explicit .asInstanceOf[T] with the method you've written:
callback(a.asInstanceOf[T])
Though, what you're trying to achieve is typically done with typeclass in Scala. I let the reader search about it but the general idea is you would have your method defined like this:
def test[T](callback: T => Unit)(implicit converter: ConverterFromString[T]): Unit = {
callback(converter.fromString(a))
}
And there would exist in scope some values of ConverterFromString for only some types you know how to handle.
The huge benefit of this approach is to be type-safe and if will raise errors at compile time rather than runtime if a type cannot be handled.
Using typeclass as suggested by #Gaƫl J works:
trait Converter[A] {
def conveterFromString(a: String): A
}
object Converter {
implicit val stringConverter: Converter[String] = new Converter[String] {
def conveterFromString(x: String): String = x
}
implicit val arrayConverter: Converter[Array[Char]] = new Converter[Array[Char]] {
def conveterFromString(x: String): Array[Char] = x.toCharArray
}
}
class PatternMatching {
val a = "test"
def test[A](callback: A => Unit)(implicit converter: Converter[A]): Unit =
callback(converter.conveterFromString(a))
}
Related
I have two case class Customer and CustomerResponse and implicit function for conversion from customer to response
case class Customer(name:String)
case class CustomerResponse(customerName:String)
object CustomerImplicits {
implicit def customer2CustomerResponse(value : Customer) =
new CustomerResponse(value.name)
}
Im trying to create a generic function where I can pass lot of classes and perform operation
def getEntityArray[T,U](idArray:Array[String]):Array[U] = {
val records:Array[T] = getRecords[T](idArray)
if(!records.isEmpty) {
val ret = records.map( aRec => aRec:U)
return ret
}
else
return Array.empty[U]
}
arr = getEntityArray[Address,AddressResponse](array)
I'm getting an error T does not conform to expected type U. Is there any way to pass the implicit conversion CustomerImplicits to the getEntityArray function
Consider changing from Array to List and pass implicit conversion implicit ev: T => U argument like so
def getEntityList[T, U](ts: List[T])(implicit ev: T => U): List[U]
For example,
def getEntityList[T, U](ts: List[T])(implicit ev: T => U): List[U] = {
ts.map(ev)
}
import CustomerImplicits._
getEntityList[Customer, CustomerResponse](List(Customer("Picard"), Customer("Worf")))
outputs
res0: List[CustomerResponse] = List(CustomerResponse(Picard), CustomerResponse(Worf))
I think you're trying to achieve this:
import scala.reflect._
def getEntityArray[T, U: ClassTag](idArray: Array[String])(implicit t2u: T => U): Array[U] = {
val records: Array[T] = getRecords[T](idArray)
if(!records.isEmpty)
records.map( r => r: U)
else
Array.empty
}
import CustomerImplicits._
getEntityArray[Customer, CustomerResponse](Array.empty)
However, it doesn't seem to be a good approach for several reasons:
Generic types have no relation with the parameters, that's why you can't make use of type inference.
You are using Array, which is basically a Java type, that's why you need to pass the ClassTag context bound to U for it to work. You can try List instead.
Using implicit conversions this way makes the code less readable. Maybe you can just call it explicitly records.map(t2u), and even make t2u a normal parameter.
Try this:
implicit class Convert[T](req: List[T]) {
import CustomerImplicits._
def gerResp: List[CustomerResponse] = {
req.flatMap {
case customer: Customer => customer :: Nil
case _ => List.empty[CustomerResponse]
}
}
}
val customer = List(Customer("A"), Customer("B"), Customer("C"))
println(customer.gerResp)
in place of asInstanceOf you can do any operation you want which is converting T => U
I think this is what you are looking for.
Look at this code.
trait SomeMix {
}
trait Processor[T] {
def processMix(t: T with SomeMix) = {
println("processing T with Mix")
}
def processAsUsual(t:T)= {
println("processing T")
}
def process(t:T) = {
t match {
case mix: SomeMix => processMix(mix) // <---- error here
case _ => processAsUsual(t)
}
}
}
Stupid Scala compiler shows error here:
Error:(22, 39) type mismatch;
found : mix.type (with underlying type SomeMix)
required: T with SomeMix
case mix: SomeMix => processMix(mix)
It does not understand that expression I matching to SomeMix is already of type T. Ok lets help him. Changed code:
def process(t:T) = {
t match {
case mix: T with SomeMix => processMix(mix) // <---- warning here
case _ => processAsUsual(t)
}
}
Now it agrees that all is correct but show warning:
Warning:(22, 17) abstract type pattern T is unchecked since it is eliminated by erasure
case mix: T with SomeMix => processMix(mix)
Is any good way to avoid both error and warning here?
Scala compiler is not stupid. You can't check t is instance of T with SomeMix because of type erasure. Instead of dynamic type dispatching try to use typeclasses with static dispatching.
For example
trait SomeMix {
def someMethod: String = "test2"
}
class SomeType
def process[T](t: T)(implicit P: Process[T]): Unit = P.process(t)
trait Process[T] {
def process(t: T): Unit
}
implicit val processString: Process[SomeType] = s =>
println(s"processing $s as usual")
implicit val processStringWithSomeMix: Process[SomeType with SomeMix] = s =>
println(s"processing $s with mix ${s.someMethod}")
process(new SomeType)
process(new SomeType with SomeMix)
Since, as you mention, it's definitely an instance of T, you can just suppress the unchecked warning:
case mix: (T #unchecked) with SomeMix
Note that it's still unchecked and at runtime only tests that the matchee is an instance of SomeMix; if you change to e.g.
def process(t: Any) = ...
you'll get bad results.
Like this?
trait SomeMix {
}
trait Processor[T] {
def processMix(t: SomeMix) = {
println("processing SomeMix")
}
def processAsUsual(t:T)= {
println("processing T")
}
def process(t:T) = {
t match {
case mix: SomeMix => processMix(mix)
case _ => processAsUsual(t)
}
}
}
You can do this at compile time like #ppressives proposed.
If you really want to do this at runtime you should find a way to keep types there after compile time. In Scala standard way to do this is TypeTags.
Try
import reflect.runtime.universe.{TypeTag, typeOf}
def typ[A: TypeTag](a: A) = typeOf[A]
def process(t: T)(implicit ev: TypeTag[T with SomeMix], ev1: TypeTag[T]) = {
t match {
case mix if typ(t) <:< typeOf[T with SomeMix] => processMix(mix.asInstanceOf[T with SomeMix])
case _ => processAsUsual(t)
}
}
val p = new Processor[Int] {}
p.process(10) //processing T
val p1 = new Processor[Int with SomeMix] {}
val ten = 10.asInstanceOf[Int with SomeMix]
p1.process(ten) //processing T with Mix
Check
Pattern match of scala list with generics
Pattern matching on generic type in Scala
For example I have code looks like this:
class Parent
class Child1 extends Parent
class Child2 extends Parent
class Foo {
def retrieve(arg: String): List[Parent] = {
arg match {
case "Child1" => get[Child1]()
case "Child2" => get[Child2]()
}
}
def get[T: Manifest](): List[T] = ...
}
In the retrieve method, I want to simplify the code into one get method call only like this:
def retrieve(arg: String): List[Parent] = {
val t = arg match {
case "Child1" => ?
case "Child2" => ?
}
get[t]()
}
Is it possible to achieve this in scala?
UPDATE:
I tried the solution from the answer here but I got a problem, it doesn't work with overloaded get method, for example:
def get[T: Manifest](x: String): List[T] = ...
def get[T: Manifest, U: Manifest](x: String): List[(T, U)] = ...
For example, in the retrieve:
val t = arg match {
case "Child1" => manifest[Child1]
case "Child2" => manifest[Child2]
}
get("test")(t)
I got ambiguous reference to overloaded definition compile error on the line get("test")(t).
Manifest is basically deprecated. :
In Scala 2.10, scala.reflect.ClassManifests are deprecated, and it is
planned to deprecate scala.reflect.Manifest in favor of TypeTags and
ClassTags in an upcoming point release. Thus, it is advisable to
migrate any Manifest-based APIs to use Tags.
You should consider using the more modern ClassTag or TypeTag. In this case, ClassTag works better (since TypeTags can't be used in pattern matching):
def retrieve(arg: String): List[Parent] = {
val t = arg match {
case "Child1" => classTag[Child1]
case "Child2" => classTag[Child2]
}
get(t)
}
def get[T : ClassTag]: List[T] = list collect {
case x: T => x
}
You can read more about ClassTags, TypeTags, and their relationship to Manifest in the docs here.
In case it's not clear, this works because the type constraint on T is a context bound, meaning the method signature of get is equivalent to:
def get[T](implicit ev: ClassTag[T]): List[T]
So, when we call get(t), we're explicitly specifying the implicit parameter. Read more about context bounds here.
If the context bound or implicit parameter is confusing, you can also achieve your goals by making get non-generic:
def get(c: ClassTag[_]) = list collect {
case x if ClassTag(x.getClass) == c => x
}
This non-generic, non-implicit version might help you resolve your overloading issue.
Your question boils down to how to retrieve the Manifest of a given type. This can be done using the manifest method. Then you can explictly pass the manifest, to get.
class Foo {
def retrieve(arg: String): List[Parent] = {
val t = arg match {
case "Child1" => manifest[Child1]
case "Child2" => manifest[Child2]
}
get(t)
}
def get[T <: Parent: Manifest]: List[T] = ...
}
As a side note, you should probably use a map to retrieve the manifests (rather than pattern matching) so as to make it more easily editable, or possibly at one point replacing the hard-coded list of types with some init-time computation:
object Foo {
private val manifestByName = Map[String, Manifest[_<:Parent]](
"Child1" -> manifest[Child1],
"Child2" -> manifest[Child2]
)
}
class Foo {
def retrieve(arg: String): List[Parent] = {
val t = Foo.manifestByName.getOrElse(arg, sys.error(s"Invalid class name $arg"))
get(t)
}
def get[T <: Parent: Manifest]: List[T] = { println(manifest[T]); Nil }
}
Finally, note that Manifest is now deprecated, it was superseded with ClassTag\ TypeTag.
I am trying to implement a ReadJsonCodec of sorts using the automatic type class derivation mechanism in Shapeless.
Here is my ReadCodecCompanionObject:
object ReadCodec extends LabelledProductTypeClassCompanion[ReadCodec] {
implicit object StringCodec extends SimpleCodec[String] {
def read(j: Json): String = j.stringOr(throw ...)
}
implicit object IntCodec ...
implicit object BooleanCodec ...
implicit object LongCodec ...
implicit object ShortCodec ...
implicit object DoubleCodec ...
implicit object BigDecimalCodec ...
implicit def readCodecInstance: LabelledProductTypeClass[ReadCodec] = new LabelledProductTypeClass[ReadCodec] {
def emptyProduct = new ReadCodec[HNil] {
// This will silently accept extra fields within a JsonObject
// To change this behavior make sure json is a JsonObject and that it is empty
def read(json: Json) = HNil
}
def product[F, T <: HList](name: String, FHead: ReadCodec[F], FTail: ReadCodec[T]) = new ReadCodec[F :: T] {
def read(json: Json): F :: T = {
val map = castOrThrow(json)
val fieldValue = map.getOrElse(name, throw new MappingException(s"Expected field $name on JsonObject $map"))
// Try reading the value of the field
// If we get a mapping exception, intercept it and add the name of this field to the path
// If we get another exception, don't touch!
// Pitfall: if handle did not accept a PartialFunction, we could transform an unknow exception into a match exception
val head: F = Try(FHead.read(fieldValue)).handle{ case MappingException(msg, path) => throw MappingException(msg, s"$name/$path")}.get
val tail = FTail.read(json)
head :: tail
}
}
def product[A, T <: HList](name: String, FHead: ReadCodec[Option[A]], FTail: ReadCodec[T]) = new ReadCodec[Option[A] :: T] {
def read(json: Json): Option[A] :: T = {
val map = castOrThrow(json)
val head: Option[A] = map.get(name).map { fieldValue =>
Try(FHead.read(fieldValue)).handle{ case MappingException(msg, path) => throw MappingException(msg, s"$name/$path")}.get.get
}
val tail = FTail.read(json)
head :: tail
}
}
def project[F, G](instance: => ReadCodec[G], to : F => G, from : G => F) = new ReadCodec[F] {
def read(json: Json): F = from(instance.read(json))
}
}
}
That's somewhat of a complicated piece of code to just grasp quickly but is really fairly simple once you understand it. The important part is the two def product methods. The problem I am having is that I want this codec to accept a Json AST that is missing a field if that field would be mapped to a value of type Option[A]. This means that I need the product function to know if the head of the HList is of type Option[A] or not.
Concretely:
case class Foo(a: String, b: Option[Boolean])
val test = read[Foo](json"""{"a" : "Beaver"}""") // should work
But currently this would fail because it makes no distinction for Option and expects a field b. I tried two ways of fixing this and neither of them worked.
The first one and the cleanest one is to overload the product method with a version where the F type parameter is replaced with Option[A]. This approach is fairly clean, although I am not sure whether or not it would play well with the shapeless derivation macro. However, it is not possible because Scala does not support the ability to overload functions when the type signature after erasure is the same. This is the version that is above. Unfortunately, this does not currently compile with the Scala compiler.
The second approach was to use a TypeTag to find out at runtime if F is of type Option[_] and behave appropriately. This version would almost certainly be less elegant and involve a cast but I could live with it. However, it seems impossible because the addition of a TypeTag changes the signature of the product method (adding an implicit parameter) and then the compiler complains that I am not defining the abstract method product.
Does anyone have any suggestions on the best way to proceed.
You need to get a typeclass with information about F passed through. But you're already passing a typeclass around, in the form of ReadCodec. So the solution is to replace that with one that contains all the information you need:
trait ReadCodecAndTypeTag[A] {
val rc: ReadCodec[A]
val tt: TypeTag[A]
}
But in that case you might as well delegate the decoding-from-optional-value-in-a-map to this typeclass as well:
trait OReadCodec[A] {
val rc: ReadCodec[A]
def missingField(name: String, map: Any): A =
throw new MappingException(s"Expected field $name on JsonObject $map")
}
implicit object StringCodec extends OReadCodec[String] {
val rc = new ReadCodec[String] {...}
}
implicit object IntCodec ...
...
implicit def OptionCodec[A](implicit orc: OReadCodec[A]) =
new OReadCodec[Option[A]] {
val rc = ...
override def missingField(name: String, map: Any) = None
}
...
def product[F, T <: HList](name: String, FHead: OReadCodec[F], FTail: OReadCodec[T]) =
new OReadCodec[F :: T] {
val rc = new ReadCodec[F :: T] {
def read(json: Json): F :: T = {
val map = castOrThrow(json)
val fieldValue = map.getOrElse(name, FHead.missingField(name, map))
val head: F = ...
...
}
}
}
implicit def ReadCodecFromOReadCodec[A](implicit orc: OReadCodec[A]) = orc.rc
I'm trying to write a factory method that returns Foo[T: ClassManifest] (which I need due to the requirements of the library to which I am passing the result) without knowing specifically what T is. My code is equivalent to:
class Foo[T: ClassManifest] (t: T) {
def getValue: T = t
override def toString: String = "Foo["+t+": "+t.getClass().getName()+"]"
}
object FooFactory {
def parse (value: String): Foo[_] = {
val rest = value.substring(1)
value.head match {
case 's' => new Foo[String](rest)
case 'i' => new Foo[Int](rest.trim.toInt)
case 'd' => new Foo[Double](rest.trim.toDouble)
}
}
}
class FactoryTestSuite extends FunSuite {
def printIt [T: ClassManifest] (t: Foo[T]): Unit =
println(t)
test("Creation") {
printIt(FooFactory.parse("sabc"))
printIt(FooFactory.parse("i123"))
printIt(FooFactory.parse("d1.23"))
}
}
This won't compile - each of the creation test lines complain that it could not find implicit value for evidence parameter of type ClassManifest[_$1]
Is there any way to do this? Or do the compile-time requirements for ClassManifest make this simply impossible?
Result type of parse is Foo[_], so T is unknown. You can't get ClassManifest for unknown type. Just remove ClassManifest (and T) from printIt:
def printIt(t: Foo[_]): Unit = println(t)
printIt(FooFactory.parse("sabc"))
// Foo[abc: java.lang.String]
printIt(FooFactory.parse("i123"))
// Foo[123: java.lang.Integer]
printIt(FooFactory.parse("d1.23"))
// Foo[1.23: java.lang.Double]
Implicit parameter of type ClassManifest[T] of Foo constructor is resolved here:
case 's' => new Foo[String](rest)
Compiler knows that T here is String. It can create an implicit argument of type ClassManifest[String].
To get ClassManifest in method printIt you could add it as field in class Foo:
class Foo[T: ClassManifest] (t: T) {
val manifest = implicitly[ClassManifest[T]]
...
}
def printIt (t: Foo[_]): Unit =
println(s"t=$t, manifest=${t.manifest}")