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)
Related
I need to get a Numeric[T] if available (so I guess an Option[Numeric[T]]) for the following situation:
class Foo[T]() {
def t:T
def doSomeProcessing():Unit = ... // This is where I need an Option[Numeric[T]]
}
class Bar {
def foos: Seq[Foo[_]]
def doSomethingWithFoos():Unit = {
for (foo <- foos) {
foo.doSomeProcessing()
}
}
}
I can add ClassTag or TypeTag as necessary / helpful, but I'd like to avoid an explicit listing of each and every possible Numeric, which is what I have right now:
val numOpt: Option[Numeric[T]] = classTag[T] match {
case longTag if longTag == classTag[Long] => Some(Numeric.LongIsIntegral.asInstanceOf[Numeric[T]])
case intTag if intTag == classTag[Int] => Some(Numeric.IntIsIntegral.asInstanceOf[Numeric[T]])
...
case _ => None
}
Is there a more elegant / comprehensive solution? Thanks!
Edit: I tried doing:
class Foo[T](implicit num: Numeric[T] = null) {
def t:T
val numOpt:Option[Numeric[T]] = Option(num)
}
But that didn't work (numOpt = None for T = Long), probably because Foo is actually part of a long class hierarchy with multiple this / super calls...
Update: the issue is that Foo actually has four constructors, and all need to take an (implicit num: Numeric[T] = null), but only one of them is allowed to have a default parameter. I guess I would have to find a way to get rid of three of them, or manually feed in null as needed.
Try an implicit Numeric parameter with a default value:
class Foo[T] private(val t: T)(val numeric: Option[Numeric[T]])
object Foo {
def apply[T](t: T)(implicit numeric: Numeric[T] = null) = new Foo(t)(Option(numeric))
}
You can use it as such
class Bar {
//Note that I've explicitly put in Foo[Int] here because it doesn't understand it otherwise (not sure why).
def foos: Seq[Foo[_]] = Seq(Foo("blah"), Foo[Int](39))
def doSomethingWithFoos():Unit = {
for (foo <- foos) {
println(foo.t)
foo.numeric match {
case Some(num: Numeric[foo.t.type]) => println(num.plus(foo.t, foo.t))
case None => println("Not numeric")
}
}
}
}
Output:
blah
Not numeric
39
78
<script src="https://scastie.scala-lang.org/CDSbri6WQwSYtIoR4Swl8A.js"></script>
If you don't want the boilerplate of an apply method, you can also define your own method to supply Option instances and directly use an implicit in your constructor.
class Foo[T](val t: T)(implicit val numeric: Option[Numeric[T]])
implicit def implicitOption[T](implicit t: T = null): Option[T] = Option(t)
Link to Scastie: https://scastie.scala-lang.org/pUOw5tFNRtGZVbHNHx7QYw
Otherwise, you can use a nullable type instead of an Option.
class Foo[T](val t: T)(implicit val numeric: Numeric[T] = null)
Link to Scastie: https://scastie.scala-lang.org/AOGNZSirT0C7Cy0Po6vZXw
I have the following operations: OpSUM, OpAVG, OpSTD, ... which I would like to implement for Int, Float, String and additional types.
The brute force way might be something like this:
trait Operation
case class OpSUM[T: TypeTag]() extends Operation {
typeOf[T] match {
case t if t =:= typeOf[String] => Do some string work
case t if t <:< typeOf[Int] => Do some Int work
...
}
}
case class OpAVG[T: TypeTag]() extends Operation {
typeOf[T] match {
case t if t =:= typeOf[String] => Do some string work
case t if t <:< typeOf[Int] => Do some Int work
...
}
}
...
Is there a better scala way to do this?
The main problem I see here is that Op and the type are coupled, meaning for each operation the type does different work.
If you try approach with type classes (as #mrmcgreg proposed in his comment) this can look like:
trait OpSUM[T] {
def doSomeWork
}
object OpSUM {
implicit val stringCase: OpSUM[String] = new OpSUM[String] {
override def doSomeWork = ???
}
implicit def intCase[T <: Int]: OpSUM[T] = new OpSUM[T] {
override def doSomeWork = ???
}
}
trait OpAVG[T] {
def doSomeOtherWork
}
object OpAVG {
implicit val stringCase: OpAVG[String] = new OpAVG[String] {
override def doSomeOtherWork = ???
}
implicit def intCase[T <: Int]: OpAVG[T] = new OpAVG[T] {
override def doSomeOtherWork = ???
}
}
// ...
I link also this explanation of Type Classes by Daniel Westheide since the application domain he uses for his post looks similar to yours.
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.
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 write a generic method f[T](id:String) that is something like this:
case class A(x:String)
case class B(y:String)
case class C(z:String)
def f[T](id:String): T = { /* equivalent to T(id) */ }
val result1:A = f[A]("123") // returns A("123")
val result2:B = f{B]("345") // returns B("345")
val result3:C = f[C]("567") // returns C("567")
Unfortunately I cannot figure out how to work with the type T inside the method, besides using reflection. By "working with the type T" i mean for example being able to do something like the following, which I know doesn't work (for illustration purposes only):
T match {
case A => A(id)
case B => B(id)
}
or simply invoke T(ID) to create a new object of whatever type T is.
I can of course break up this into three methods:
def f1(id:String): A = { A(id) }
def f2(id:String): B = { B(id) }
def f3(id:String): C = { C(id) }
val result1:A = f1("123") // returns A("123")
val result2:B = f2("345") // returns B("345")
val result3:C = f3("567") // returns C("567")
but I'm hoping there is a way to keep it as one generic method to avoid some ugly boilerplate code duplication, and still be nearl as fast as the tree method version.
If you do not want to use reflection (ClassTag or TypeTag), you could use a Factory type class to achieve the desired functionality (unless it defeats the purpose of your generic function by generating a lot of duplicated simple code ;)).
case class A(s: String)
case class B(s: String)
case class C(s: String)
trait Factory[T] extends ((String) => T) {
def apply(arg: String): T
}
object Factory {
implicit object AFactory extends Factory[A] {
override def apply(arg: String): A = A(arg)
}
implicit object BFactory extends Factory[B] {
override def apply(arg: String): B = B(arg)
}
implicit object CFactory extends Factory[C] {
override def apply(arg: String): C = C(arg)
}
}
def create[T : Factory](arg: String): T = implicitly[Factory[T]].apply(arg)
create[A]("foo") | -> res0: A = A(foo)