I have a map with a getter method. The key is always a String, the value is Any.
I want to allow the caller to use a method like the followings
get[Int](k: String)
get[Boolean](k:String)
and inside this method convert the string to the specific type specified by the user. The immediate solution came to my mind was
def get[T](k: String): T = k.asInstanceOf[T]
which does not work. Then I tried with
def cast[T](x: String, classTag: ClassTag[T]): T = classTag match {
case Int => x.toInt
case Boolean => x.toBoolean
...
}
which does not compile. I am not sure this is even possible. Any idea or I need to write all the methods I want? For example
def getInt(k: String): Int
def getBoolean(k: String): Boolean
...
This is a classical use case for typeclass pattern widely used in scala. I assume that you have a custom implementation of Map and get method.
trait Converter[T]{ // typeclass
def convert(t:String):T
}
implicit object ToIntConverter extends Converter[Int] {
def convert(t:String):Int = t.toInt
}
implicit object ToBooleanConverter extends Converter[Boolean] {
def convert(t:String):Boolean = t.toBoolean
}
// vvv approach bellow works starting from scala 2.12 vvv
//
// implicit val ToBooleanConverter: Converter[Boolean] = s => s.toBoolean
// implicit val ToIntConverter : Converter[Int] = s => s.toInt
def get[T](k:String)(implicit cv: Converter[T]):T= cv.convert(k)
println(get[Int]("1"))
println(get[Boolean]("true"))
I got the below to work.
val anyMap: Map[String, Any] = Map(
"a" -> 1,
"b" -> true
)
def getInst[T](amap: Map[String, Any])(k: String): T = amap.get(k) match {
case Some(thing) => thing.asInstanceOf[T]
case None => throw new IllegalArgumentException
}
getInst[Int](anyMap)("a")
getInst[Boolean](anyMap)("b")
It's not very safe to have something like Map[String, Any] as the cast might fail. Probably best to introduce some ad-hoc polymorphism in your map (not sure).
Related
Curious if anyone has a creative approach for the following:
def toDouble(any: Any): Option[Double] = // { if any has a .toDouble method call it else return None }
For instance, Int, String, Long all have a .toDouble method. I'd like it to be called if it exist (even non primitive types).
Ideally something like this (without .toString'ing everything first)
def toDouble(any: Any): Option[Double] = {
case any.hasToDouble => Try(any.toDouble).toOption
case _ => None
}
You can use
def doubleFromAny(in: Any): Option[Double] = {
Try{in.asInstanceOf[{def toDouble: Double}].toDouble}.toOption
}
The problem with this is any toDouble provided through an implicit won't work (so the string "4.5" would give you None). I also expect performance would not be great.
In the end, you need to figure out what types are possible and use something like Jon Anderson's answer to check and cast each type.
You can use pattern matching. This has the additional benefit of giving you more explicit control over how the conversion is done. (Eg, if you wanted to try additional string parsing)
def toDouble(any: Any): Option[Double] = {
any match {
case n:Int => Some(n.toDouble)
case n:Long => Some(n.toDouble)
case n:Double => Some(n.toDouble)
case s:String => Try(s.toDouble).toOption
case _ => None
}
}
def toDouble(a: Any): Option[Double] = try {
if (a == null) None else {
Some(a.toString.toDouble)
}
} catch {
case scala.util.control.NonFatal(e) => None
}
Others have suggested good answers. Another way I thought of doing was using implicit object. For your above example you could write something like:
sealed trait ImplicitType[T]
object ImplicitType{
implicit object IntType extends ImplicitType[Int]
implicit object StringType extends ImplicitType[String]
implicit object LongType extends ImplicitType[Long]
implicit object DoubleType extends ImplicitType[Double]
}
def toDouble[T : ImplicitType](n: T) : Option[Double] = {
Try(n.toString.toDouble).toOption
}
The above works because, the compiler constraint is from the availability of implicit objects in ImplicitType companion object. The context bound implicit def f: ImplicitType[T] by default searches for implicit objects inside companion object of ImplicitType. So now you can do things like:
val foo = toDouble(1) // Some(1.0)
val foo1 = toDouble("2") //Some(2.0)
val foo2 = toDouble(1L) //Some(1.0)
val foo3 = toDouble("s") //None
val foo4 = toDouble(1.23456e300d) //Some(1.23456E300)
In this way your toDouble function does not change at all. I couldn't think of a way to avoid toString sorry. Hope this works for you.
I am trying to support an abstraction of an ID type for a framework. Example here:
object AmINecessary {
case class StringConverter[T](op: String => T)
implicit val toInt = new StringConverter[Int](_.toInt)
implicit val toLong = new StringConverter[Long](_.toLong)
}
class Foo[ID] {
// ID can be String, Long, or Int
import AmINecessary._
// If ID is string, return string, otherwise convert to ID
def getID(id: String)(implicit c: StringConverter[ID] = null): ID = if (c == null) id.asInstanceOf[ID] else c.op(id)
}
This is then used as:
val fooString = new Foo[String]
val fooLong = new Foo[Long]
val fooInt = new Foo[Int]
fooString.getID("asdf") // "asdf":String
fooLong.getID("1234") // 1234:Long
fooInt.getID("1234") // 1234:Int
fooInt.getID("asdf") // java.lang.NumberFormatException
This works as expected. My questions are:
using an optional implicit by defaulting it to null then branching on it feels bad. What is the scala way to accomplish that?
Is it really necessary to write implicit conversions for a string to long or int?
I think the best option would be to simply add an implicit StringConverter[String] and remove the default null value.
That way your fooString works without risking a ClassCastException for every other type.
object AmINecessary {
case class StringConverter[T](op: String => T)
implicit val toInt = new StringConverter[Int](_.toInt)
implicit val toLong = new StringConverter[Long](_.toLong)
implicit val idConverter = new StringConverter[String](identity)
}
class Foo[ID] {
import AmINecessary.StringConverter
def getID(id: String)(implicit c: StringConverter[ID]): ID = c.op(id)
}
Regarding your question 2, the type class approach is not really necessary (but note that there are no implicit conversions here). You can also do it like this:
abstract class Foo[ID] {
def getID(id: String): ID
}
class FooInt extends Foo[Int] {
def getID(id: String) = id.toInt
}
class FooLong extends Foo[Long] {
def getID(id: String) = id.toLong
}
class FooString extends Foo[String] {
def getID(id: String) = id
}
1) About implicit defaulting to null, you could just:
object Unsafe {
implicit val toT[T] = new StringConverter[T](_.asInstanceOf[T])
}
2) It doesn't seem as a good idea. First, because you're hiding asInstanceOf, which is unsafe operation (potential runtime exception). Second, the more explicit conversion is - the better.
If you expect some complex transformations - it's better to return option from your getID method:
def getId[T](id: String)(converter: Option[StringConverter] = None) = converter.map(_.op(id))
However, default parameters aren't the best approach either. I'd stick with compile-time error requiring user to either write own converter or explicitly do an asInstanceOf, in general.
In your concrete case asInstanceOf doesn't make much sense as the only type it would work for is String, like getId[String], so what's the point of calling getId then?
I have the following code and I wonder if the nasty thing could be removed. Override doesn't work if I add implicit parameter.
class FromEnumFormat[T <: Enum[T]] extends JsonFormat[T] {
override def read(json: JsValue): T = readit(json)
def readit(json: JsValue)(implicit m: Manifest[T]): T = {
val EnumerationClass = m.runtimeClass.asInstanceOf[Class[T]]
json match {
case s: JsString if EnumerationClass.getEnumConstants.map(_.toString.toLowerCase).contains(s) => Enum.valueOf(EnumerationClass, s.value.toUpperCase()).asInstanceOf[T]
case unknown => deserializationError(s"unknown Status: $unknown")
}
}
override def write(obj: T): JsValue = JsString(obj.name().toLowerCase)
}
Is there a way how to get rid of this line
override def read(json: JsValue): T = readit(json)
The question is essentially: Are the implicit parameters part of method signature?
UPDATE:
Code doesn't compile. So correct solution should be:
class FromEnumFormat[T<: Enum[T]] extends JsonFormat[T] {
implicit val m: Manifest[T] = ???
override def read(json: JsValue): T = {
val EnumerationClass = m.runtimeClass.asInstanceOf[Class[T]]
json match {
case s :JsString if EnumerationClass.getEnumConstants.map(_.toString.toLowerCase).contains(s) => Enum.valueOf(EnumerationClass ,s.value.toUpperCase()).asInstanceOf[T]
case unknown => deserializationError(s"unknown Status: ${unknown}")
}
}
override def write(obj: T): JsValue = {JsString(obj.name().toLowerCase)}
}
The question is how to access Manifest? I am using Scala 2.10
UPDATE:
Find that the issue is with scala reflection not with implicits and overrides, hence closing this question.
To answer your question, yest, implicit parameters are part of method signature. However, as it is implicit, this means you can call the def readit(json: JsValue)(implicit m: Manifest[T]): T function without mentioning it, as long as it has been declared somewhere in the code :
implicit val manifest = /* whatever a Manifest is*/
readit(jsonValue)
Could you please provide an example of what you'd like to do ?
Your final solution is nearly correct, but it has m in the wrong place, it should be a class parameter instead:
class FromEnumFormat[T<: Enum[T]](implicit m: Manifest[T]) extends JsonFormat[T] {
override def read(json: JsValue): T = {
val EnumerationClass = m.runtimeClass.asInstanceOf[Class[T]]
json match {
case s :JsString if EnumerationClass.getEnumConstants.map(_.toString.toLowerCase).contains(s) => Enum.valueOf(EnumerationClass ,s.value.toUpperCase()).asInstanceOf[T]
case unknown => deserializationError(s"unknown Status: ${unknown}")
}
}
override def write(obj: T): JsValue = {JsString(obj.name().toLowerCase)}
}
This way the compiler can insert it when creating a FromEnumFormat with a specific enum:
val format = new FromEnumFormat[TimeUnit]
If you want to create a generic FromEnumFormat[T], though, you'll have to pass implicit m: Manifest[T] as an argument:
def doSomethingWithFormat[T <: Enum[T]](implicit m: Manifest[T]) = {
val format = new FromEnumFormat[T]
...
}
Implicit parameters are not exactly part of the signature. But So you cannot add an implicit parameter by means of overloading.
Here's why. Multiple parameter list syntax is just a syntactic sugar. The code
def readit(json: JsValue)(implicit m: Manifest[T]): T = ???
gets desugared to
def readit(json: JsValue): Function1[Manifest[T], T] = {
def inner(implicit m: Manifest[T]): T = ???
inner
}
So as you see the real type of readit just doesn't match the type of read, thus it is not a proper override.
UPD.
As Alexey pointed out formally multiple parameter list contributes to type signature (see section 4.6 Function Declarations and Definitions of scala spec).
A function declaration has the form def fpsig: T, where f is the function's name, psig is its parameter signature and T is its result type.
A parameter signature consists of an optional type parameter clause
[tps], followed by zero or more value parameter clauses
(ps1)…(psn).
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