I've got a typeclass pattern in scala and I'd like a method that can be called against any type and return an option based on whether there is an appropriate typeclass available in scope. Concretely, I have:
trait Truthy[A] {
def toBoolean(a:A):Boolean
def unapply(a:Any):Option[Boolean]
}
object Truthy {
implicit object IntTruthy extends Truthy[Int] {
def toBoolean(i:Int) = i == 1
def unapply(a:Any) = a match {
case i:Int => Some(toBoolean(i))
case _ => None
}
}
implicit object BoolTruthy extends Truthy[Boolean] {
def toBoolean(b:Boolean) = b
def unapply(a:Any) = a match {
case i:Boolean => Some(toBoolean(i))
case _ => None
}
}
implicit object StringTruthy extends Truthy[String] {
def toBoolean(s:String) = Set("t", "true", "yes", "y").contains(s.toLowerCase)
def unapply(a:Any) = a match {
case i:String => Some(toBoolean(i))
case _ => None
}
}
def truthy[A](a:A)(implicit ev:Truthy[A]) = ev.toBoolean(a)
}
The truthy method is fine when I know the type of my argument, but I'm consuming data from a source that lacks that type info, so I'd like a function with signature Any => Option[Boolean] that will try all of the Truthy implementations in scope and return the result if one can be found. Obviously I could write
def getTruth(a:Any) = a match {
case IntTruthy(b) => Some(b)
case BoolTruthy(b) => Some(b)
case StringTruthy(b) => Some(b)
case _ => None
}
but that would defeat the whole purpose of the 'openness' of typeclasses.
The ability of the compiler to determine a valid implicit Truthy is limited by the available information at compile time. That means, from the moment you're working with an Any, which says nothing at all of the type, you'll have to "manually" identify the A type, so the compiler can find the Truthy you need.
Then your getTruth would look like:
def getTruth(any: Any): Option[Boolean] = any match {
case i : Int => Some(truthy(i))
case b : Boolean => Some(truthy(b))
...
case _ => None
}
Chirlo's answer is correct. I would add for clarification that the logic to "try all of the Truthy implementations in scope" does not exist. In principle, the compiler should not instantiate every possible object just because it is in scope, unless it is actually referenced or required in some way. Hence, what is "in scope" at compile time due to adding an import would not be there in runtime at all. This can be easily tested:
object Foo {
println("initializing foo")
def sayHello() = println("hello!")
}
object Test2 {
def main(args: Array[String]): Unit = {
val me = "Daniel"
println(s"Hey, I'm $me")
Foo.sayHello()
}
}
Prints:
Hey, I'm Daniel
initializing foo
hello!
If you comment Foo.sayHello() you will see how initializing foo goes away too. The object will not be there in runtime.
In your case, adding a type explicitly allows the compiler to statically define what implicit will be instantiated and referenced (if any).
These java specs might help clarify too.
Related
I have a base class (let us name it Base) and multiple extended classes and method for validation validate which accepts Any.
I would like to check if the parameter is a subclass of Base so I can call validate method from it and also if it is List of instances of subclass of Base to do the same.
I tried the code below, but this does not compile. Is there a simple, elegant way of doing this?
class Base {
def validate(): Unit = {}
}
class Extended1 extends Base {
override def validate(): Unit = {
// some checks
}
}
def validate(param: Any): Unit = {
param match {
case b: Base => b.validate()
// this is not working
case l: List[+Base] => l.foreach(_.validate())
case _ => // do nothing
}
}
UPDATE:
I can use override of methods. I have some more checks which I removed from question, and that was mistake, sorry.
So:
def validate(param: Any): Unit = {
if (Option(param).isEmpty) throwMissingReqFieldException(param)
param match {
case b: Base => b.validate()
case _ =>
}
}
def validate(param: List[Any]): Unit = {
if (Option(param).isEmpty || fieldValue.isEmpty) throwMissingReqFieldException(param)
// here I would like to recursively call validate if possible, maybe this is the solution
param.foreach(x => validate(x))
}
Try approach with a type class
trait Validate[T] {
def validate(t: T): Unit
}
object Validate {
implicit def defaultValidate[T]: Validate[T] = _ => ()
implicit val baseValidate: Validate[Base] = _.validate()
implicit def baseListValidate[B <: Base]: Validate[List[B]] = _.foreach(_.validate())
}
def validate[T](param: T)(implicit v: Validate[T]): Unit = v.validate(param)
If you absolutely need an Any as a parameter, do this:
def validate(param: Any): Unit = {
param match {
case b: Base => b.validate()
case l: List[Base] => if (list.forall(_.isInstanceOf[Base])) l.foreach(_.validate())
case _ => // do nothing
}
}
Here, the [Base] part is actually useless, but it tells the compiler to treat your list as a List[Base]. The actual check is in the if statement, where you make sure all of the objects are Base objects.
You could also do l.foreach(b => if (b.isInstanceOf[Base]) validate(b)) if you don't care that the list doesn't contain only Bases and also could also contain Strings or whatever
A better way to do it would be overloading, though:
def validate(b: Base): Unit = b.validate()
def validate(l: List[Base]): Unit = l.foreach(validate)
I have about a hundred small classes that inherit a trait. The classes are instantiated in a factory via reflection based on their names.
Class.forName(name).getConstructor().newInstance().asInstanceOf[Trait]
Now requirements have changed such that one and only one of the classes needs to take a parameter during construction. I am trying to change the factory to handle this new case. The REPL worksheet with my approach looks like this:
import java.lang.reflect.Constructor
trait T {
def p: Unit
}
class C1 extends T {
override def p = println("no ymd")
}
class C2(a: Array[String]) extends T {
override def p = println(s"year: ${a(0)}")
}
class C3(a: Array[Int]) extends T {
override def p = println(s"day: ${a(2)}")
}
val ymd = Array("2019","10","23")
val ymd_int = Array(2019,10,23)
def getT(c: Class[_]): T = {
c.getConstructors match {
case Array(c: Constructor[Array[String]]) => c.newInstance(ymd).asInstanceOf[T]
case Array(c: Constructor[Array[Int]]) => c.newInstance(ymd_int).asInstanceOf[T]
case Array(c: Constructor[_]) => c.newInstance().asInstanceOf[T]
case _ => throw new Exception("...")
}
}
getT(classOf[C1]).p
getT(classOf[C2]).p
getT(classOf[C3]).p
In the REPL, I'm using classOf instead of Class.forName because class names in the REPL are kind of wonky.
During compilation I'm getting the warnings:
Warning:(25, 23) non-variable type argument Array[String] in type
pattern java.lang.reflect.Constructor[Array[String]] is unchecked
since it is eliminated by erasure
case Array(c: Constructor[Array[String]]) =>
c.newInstance(ymd).asInstanceOf[T]
and
Warning:(26, 23) non-variable type argument Array[Int] in type
pattern java.lang.reflect.Constructor[Array[Int]] is unchecked
since it is eliminated by erasure
case Array(c: Constructor[Array[Int]]) =>
c.newInstance(ymd_int).asInstanceOf[T]
And then of course the calls to getT are failing because the three case statements look identical at run time and so all three calls are being handled by the first case.
Please Help.
Try
def getT(clazz: Class[_]): T = {
val constructor = clazz.getConstructors.head
(constructor.getParameterTypes.headOption.map(_.getSimpleName) match {
case None => constructor.newInstance()
case Some("String[]") => constructor.newInstance(ymd)
case Some("int[]") => constructor.newInstance(ymd_int)
case _ => throw new Exception("...")
}).asInstanceOf[T]
}
I'm trying to go functional, but when working on real world problems I'm struggling, I need helps with a few basics. I like the idea of a type class and to add more implicit types in future.
trait Query {
def queryDetails: QueryDetails
}
case class LocalQueryType(queryDetails: QueryDetails) extends Query
case class JdbcQueryType(queryDetails: QueryDetails) extends Query
def queryTypeFactory(queryDetails: QueryDetails): Query = {
queryDetails.platform match {
case c if queryDetails.platform.contains("-file://") => LocalQueryType(queryDetails)
case _ => JdbcQueryType(queryDetails)
}
}
Then I have a type class that looks for the local or Jdbc types, but it doesn't work as it is receiving only Query type.
I've tried using generics like:
def queryTypeFactory[T<:Query](queryDetails: QueryDetails): T = {
queryDetails.platform match {
case c if queryDetails.platform.contains("-file://") => LocalQueryType(queryDetails)
case _ => JdbcQueryType(queryDetails)
}
}
Adding Type Class:
trait QueryTask[A] {
def runQuery(a: A): String
}
object QueryTask {
def apply[A](implicit sh: QueryTask[A]): QueryTask[A] = sh
object ops {
def runQuery[A: QueryTask](a: A) = QueryTask[A].runQuery(a)
implicit class ShowOps[A: QueryTask](a: A) {
def runQuery = QueryTask[A].runQuery(a)
}
}
implicit val localQuery: QueryTask[LocalQueryType] =
instance(localQueryType => s"running local: ${localQueryType.queryDetails.command} on platform: ${localQueryType.queryDetails.platform}")
implicit val jdbcQuery: QueryTask[JdbcQueryType] =
instance(jdbcQueryType => s"running jdbc: ${jdbcQueryType.queryDetails.command} on platform: ${jdbcQueryType.queryDetails.platform}")
def instance[A](func: A => String): QueryTask[A] =
new QueryTask[A] {
def runQuery(a: A): String = func(a)
}
The idea is to not use the usual OO factory or strategy pattern.
Type class approach seems not to work in your use case.
Implicits are resolved at compile time. So in order to decide which instance you need QueryTask[LocalQueryType] or QueryTask[JdbcQueryType] compiler has to know whether type A is LocalQueryType or JdbcQueryType at compile time.
But it seems you decide that depending on whether queryDetails.platform.contains("-file://") or not i.e. at runtime.
It seems you need usual pattern mathing. You should use type class pattern when it's necessary.
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.
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.