Evaluate String as a generic function or function call in Scala - scala

I want to write a generic function functionChooser which will choose which function to use from a few options, based on a String argument.
This works:
def a (arg: String) = arg + " with a"
def b (arg: String) = arg + " with b"
def c (arg: String) = arg + " with c"
def functionChooser(func: String, additionalArg: String) = {
val f = func match {
case "a" => a _
case "b" => b _
case _ => c _
}
f(additionalArg)
}
scala> functionChooser("a", "foo")
res18: String = foo with a
I'm having trouble in making functionChooser generic, e.g. when functions a, b, and c return different case classes:
case class A(s: String)
case class B(s: String)
case class C(s: String)
def a (arg: String) = A(arg)
def b (arg: String) = B(arg)
def c (arg: String) = C(arg)
//functionChooser def as before
scala> functionChooser("a", "foo")
res19: Product with Serializable = A(foo)
I don't quite understand what I got there, I know I get an error when calling functionChooser("a", "foo").s ("error: value s is not a member of Product with Serializable").
Lastly, what I really want is that the functions would return Lists of these case classes, e.g.:
def a (arg: String) = List(A(arg))
def b (arg: String) = List(B(arg))
def c (arg: String) = List(C(arg))
So functionChooser should be generic to List[T] where T is some class.

The function functionChooser will return the most specific common super type of the case classes A, B and C. Since case classes inherit from Product and Serializable, the common super type is Product with Serializable.
If you want to access the case class field s you either have to cast the result, via pattern matching, or you provide a common base class of all your classes A, B and C which allows you to access the field.
trait Base {
def s: String
}
case class A(s: String) extends Base
case class B(s: String) extends Base
case class C(s: String) extends Base
With this type definition the return type of functionChooser would be Product with Serializable with Base and, thus, the result would allow you to access s.
If your function a, b and c return a List of the respective case class, then the return type of functionChooser would be List[Product with Serializable with Base].
Update
If you cannot change the class hierarchy, then you either have to cast the result or you could extract the necessary information in the functionChooser and wrap it in another type which contains the super set of all data you need. E.g.
def functionChooser(func: String, additionalArg: String): String = {
val f = func match {
case "a" => (a _).s
case "b" => (b _).s
case _ => (c _).s
}
f(additionalArg)
}
Note: Here I only extract the field s which is the super set of all required information.

You should return the upper common type for all three functions. Object (AnyRef) always fit.
def functionChooser(func: String, additionalArg: String) : AnyRef = {
In your case, where all possible returning values are Lists you may use more specific type:
def functionChooser(func: String, additionalArg: String) : List[_] = {
Of course that will eliminate type information. Any method should return the same type, it could not be polymorphic on it. So, you need to use .asInstanceOf[T] case further, to get this information back.
That make sense, because the actual type is unknown during runtime. e.g. the dispatcher string may be entered by user. If it would be known during compile time, then you could just use appropriate method without referring to descriptive string.
If you would like to get some common behaviour for all possible return types, than you should define a common trait for them and place common methods to it.

Related

How to get all types and column names in nested case class in a Map

case class Address( address :String ,pinCode : Int)
case class Person (a: String,b:Int ,c: Address)
def getClassDefinition[T:TypeTag] =
(typeOf[T].members.filter(!_.isMethod).map(r => (r.name -> r.typeSignature)))
val m = getClassDefinition[Address]
(pinCode ,scala.Int)
(address ,String)
val p =getClassDefinition[Person]
(c ,A$A332.this.Address)
(b ,scala.Int)
(a ,String)
I am looking for an nested result instead of just going till Address case class
If I understand the problem, it is to get a class definition that includes a name -> type signature pair for each of the the non-method members of the type. If the type signature is a standard type, that is all that is required; but for some types a nested definition is required. I've modelled this either/or case with an Either[Definition, NestedDefinition].
In this example I've chosen an isNested(...) rule that matches on the package name, but it could be any rule that identifies a class for deeper inspection.
I'm not sure if the output is in the format that you expected, but you can either modify the example code, or map the result into your own data structure.
import scala.reflect.runtime.universe._
object TypeTags {
// Define your domain name here for the isNested(...) test!
val myDomainName: String = ???
// Define some type aliases
type Definition = ((AnyRef with SymbolApi)#NameType, Type)
type EitherDefinitionOrNested = Either[Definition, NestedDefinition]
// A nested definition contains the original definition and an iterable collection of its member definitions (recursively).
case class NestedDefinition(t: Definition, m: Iterable[EitherDefinitionOrNested])
// The test to determine if a nested definition is needed.
def isNested(r: Symbol): Boolean = {
r.info.typeSymbol.fullName.startsWith(myDomainName)
}
// Obtain a class definition from a Symbol.
def classDefinition(symbol: Symbol): Iterable[EitherDefinitionOrNested] = {
symbol.typeSignature.members.filter(!_.isMethod).map {
case r # nested if isNested(r) => Right(NestedDefinition(nested.name -> nested.typeSignature, classDefinition(nested)))
case r => Left(r.name -> r.typeSignature)
}
}
// Obtain a class definition from a type.
def getClassDefinition[T: TypeTag]: Iterable[EitherDefinitionOrNested] = classDefinition(typeOf[T].typeSymbol)
// The test case
case class Address(address: String ,pinCode: Int)
case class Person(a: String, b: Int ,c: Address)
def main(args: Array[String]): Unit = {
val m = getClassDefinition[Address]
val p = getClassDefinition[Person]
println(s"address: $m")
println(s"person: $p")
}
}

How to use type information from pattern matching?

I have the following setup:
trait TypeA { override def toString() = "A" }
trait TypeB { override def toString() = "B" }
trait TypeC { override def toString() = "C" }
def foo[T](t: T) = println(t)
Now I can do something like this:
val valueB: Any = new TypeB {}
val typedValue = valueB match {
case t: TypeA => foo(t)
case t: TypeB => foo(t)
case t: TypeC => foo(t)
}
// prints "B"
If I want to generalize this pattern matching block, I can simply do:
val typedValue = valueB match {
case t => foo(t)
}
and it will work. However, in my real use case I need to explicitly state the type information when invoking the method because there is no function argument to infer it from. So if foo() was a generic method parameterized with type parameter T, but without actual parameters of that type to infer from, can I generalize this into a pattern matching with just one case statement (probably using the Reflection API)?
So, how to generalize this?
val typedValue = valueB match {
case t: TypeA => foo[TypeA]()
case t: TypeB => foo[TypeB]()
case t: TypeC => foo[TypeC]()
...
}
If I want to generalize this pattern matching block, I can simply do:
val typedValue = valueB match {
case t => foo(t)
}
In general you can't. E.g. if foo(x: TypeA), foo(x: TypeB) and foo(x: TypeC) are separate overloads. And that's the situation for your real code: you'd have to write separate methods for JsObject, etc. because those value calls just happen to have the same name; you can't write foo(x: JsValue) or foo[T <: JsValue](x: T) which would do what you want (without the same match which you want to avoid).
In the case where you do have a single polymorphic method: because generic arguments get erased, if you have def foo[T]() = ..., foo[TypeA](), foo[TypeB]() and foo[TypeC]() will execute the same actual code (this doesn't apply to classOf, isInstanceOf or asInstanceOf, but those are the only exceptions and it's because they aren't really generic methods). So you can just call foo[<type-of-valueB>]. For them to be different, foo has to have an implicit argument which depends on T, e.g.
trait Baz[A] { ... }
object Baz {
implicit val bazTypeA: Baz[TypeA] = ...
...
}
def foo[A]()(implicit baz: Baz[A]) = ...
In this case the way to avoid branching is for the method calling foo to accept the same implicit:
def bar[A](value: A)(implicit baz: Baz[A]) = foo[A]()
bar(new TypeA) // uses bazTypeA

In Scala Reflection, How to get generic type parameter of a concrete subclass?

Assuming that I have a Generic superclass:
class GenericExample[T](
a: String,
b: T
) {
def fn(i: T): T = b
}
and a concrete subclass:
case class Example(
a: String,
b: Int
) extends GenericExample[Int](a, b)
I want to get the type parameter of function "fn" by scala reflection, so I select and filter through its members:
import ScalaReflection.universe._
val baseType = typeTag[Example]
val member = baseType
.tpe
.member(methodName: TermName)
.asTerm
.alternatives
.map(_.asMethod)
.head
val paramss = member.paramss
val actualTypess: List[List[Type]] = paramss.map {
params =>
params.map {
param =>
param.typeSignature
}
}
I was expecting scala to give me the correct result, which is List(List(Int)), instead I only got the generic List(List(T))
Crunching through the document I found that typeSignature is the culprit:
* This method always returns signatures in the most generic way possible, even if the underlying symbol is obtained from an
* instantiation of a generic type.
And it suggests me to use the alternative:
def typeSignatureIn(site: Type): Type
However, since class Example is no longer generic, there is no way I can get site from typeTag[Example], can anyone suggest me how to get typeOf[Int] given only typeTag[Example]? Or there is no way to do it and I have to revert to Java reflection?
Thanks a lot for your help.
UPDATE: After some quick test I found that even MethodSymbol.returnType doesn't work as intended, the following code:
member.returnType
also yield T, annd it can't be corrected by asSeenFrom, as the following code doesn't change the result:
member.returnType.asSeenFrom(baseType.tpe, baseType.tpe.typeSymbol.asClass)
There are two approaches which I can suggest:
1) Reveal generic type from base class:
import scala.reflect.runtime.universe._
class GenericExample[T: TypeTag](a: String, b: T) {
def fn(i: T) = "" + b + i
}
case class Example(a: String, b: Int) extends GenericExample[Int](a, b) {}
val classType = typeOf[Example].typeSymbol.asClass
val baseClassType = typeOf[GenericExample[_]].typeSymbol.asClass
val baseType = internal.thisType(classType).baseType(baseClassType)
baseType.typeArgs.head // returns reflect.runtime.universe.Type = scala.Int
2) Add implicit method which returns type:
import scala.reflect.runtime.universe._
class GenericExample[T](a: String, b: T) {
def fn(i: T) = "" + b + i
}
case class Example(a: String, b: Int) extends GenericExample[Int](a, b)
implicit class TypeDetector[T: TypeTag](related: GenericExample[T]) {
def getType(): Type = {
typeOf[T]
}
}
new Example("", 1).getType() // returns reflect.runtime.universe.Type = Int
I'm posting my solution: I think there is no alternative due to Scala's design:
The core difference between methods in Scala reflection & Java reflection is currying: Scala method comprises of many pairs of brackets, calling a method with arguments first merely constructs an anonymous class that can take more pairs of brackets, or if there is no more bracket left, constructs a NullaryMethod class (a.k.a. call-by-name) that can be resolved to yield the result of the method. So types of scala method is only resolved at this level, when method is already broken into Method & NullaryMethod Signatures.
As a result it becomes clear that the result type can only be get using recursion:
private def methodSignatureToParameter_ReturnTypes(tpe: Type): (List[List[Type]], Type) = {
tpe match {
case n: NullaryMethodType =>
Nil -> n.resultType
case m: MethodType =>
val paramTypes: List[Type] = m.params.map(_.typeSignatureIn(tpe))
val downstream = methodSignatureToParameter_ReturnTypes(m.resultType)
downstream.copy(_1 = List(paramTypes) ++ methodSignatureToParameter_ReturnTypes(m.resultType)._1)
case _ =>
Nil -> tpe
}
}
def getParameter_ReturnTypes(symbol: MethodSymbol, impl: Type) = {
val signature = symbol.typeSignatureIn(impl)
val result = methodSignatureToParameter_ReturnTypes(signature)
result
}
Where impl is the class that owns the method, and symbol is what you obtained from Type.member(s) by scala reflection

Scala generics: How to declare that a type must be a case class?

I have several case classes with a count field. It's 1 by default, and I have a reduce in my code that groups duplicates and sums that value to find the number of each object. E.g.:
case class Person(name: String, count = 1)
personList.groupBy(_.name).reduce((x,y) => x.copy(count = x.count + 1))
I have this logic in several case classes, and since my logic is a bit more complicated than the example above I want to create a generic merging function.
So I've created a sealed trait with a count field. I've then changed my case classes to extend from this, e.g.:
case class Person(name: String, override val count) extends Countable
So far, so good.
However, I can't work out how to declare my merge function so that it only accepts case classes that extend Countable. Because of that, it can't find the copy method.
Here's what I have:
def merge[T <: Countable](f: T => Seq[String])(ms: Seq[T]): Vector[T] =
ms.groupBy(x => f(x).mkString("_")).mapValues(_.reduce { (x,y) =>
x.copy(count = x.count + 1) // can't find `copy`
}).values.toVector
Is there a typeclass that I can also include that means a type has a copy method (or is a case class) using Scala 2.11.7?
Update:
Countable trait is:
sealed trait Countable {
def timesSeen: Long = 1
}
How did you defined you Countable trait.
Following snippet works fine for me:
trait Countable[Z] {
def count: Int
def copy: Z
}
case class Person(name: String, override val count: Int) extends Countable[Person] {
override def copy: Person = this
}
def merge[T <: Countable[T]](f: T => Seq[String])(ms: Seq[T]): Vector[T] = {
val r = ms.groupBy(x => f(x).mkString("_")).mapValues(_.reduce { (x, y) =>
x.copy
}).values.toVector
r
}

Why are constructor parameters made into members for case classes?

{
class MyClass(name: String) {}
val x = new MyClass("x")
println(x.name) // Error name is not a member of MyClass
}
but
{
abstract class Base
case class MyClass(name: String) extends Base {}
var x = new MyClass("x")
println(x.name) // name is a member of MyClass
}
So, what's the deal with case classes? Why are all of the constructor parameters turned into variables.
name is member in both examples, but private in your first example while public in your second. Case classes make their constructor parameters public val by default.
Pattern matching is the most important but not the only application for case classes. Another important point is that they implement the equals and hashCode methods in terms of the constructor arguments (aka product elements). Therefore, case classes are very useful for defining data structures that serve as elements in sets or keys in maps. That in turn only makes sense if these elements are visible.
Compare:
class Foo(val i: Int)
val set1 = Set(new Foo(33))
set1.contains(new Foo(33)) // false!!
And:
case class Bar(val i: Int)
val set2 = Set(Bar(33)
set2.contains(Bar(33)) // true!
Two case class instances with equal parameters are equal themselves. You can imagine them representing some "constants". This implies that you should not have mutable state in them.
You can, however, use a second parameter list to exclude arguments from the equality:
case class Baz(i: Int)(val n: Long)
Baz(33)(5L) == Baz(33)(6L) // true!
Another useful feature which implies that the constructor arguments become values, is making copies. This is the way immutable data is changes—you create a new instance with a particular value changed, leaving the original value in place.
case class Person(name: String, age: Int)
val p1 = Person("Fuzzi", 33)
val p2 = p1.copy(age = 34)
The copy method uses default values for all unspecified argument, taking those values from the constructor args.
Just to be clear, the constructor arguments aren't used to create variables, they're used to create values.
If you specify val in your first example, the non-case class:
class MyClass(val name: String) {}
then you also get the argument translated into a public value, the same as is done for the case class.
In the example on the Scala-Lang site it says:
It makes only sense to define case classes if pattern matching is used
to decompose data structures. The following object defines a pretty
printer function for our lambda calculus representation:
followed by the example code:
object TermTest extends Application { def printTerm(term: Term) {
term match {
case Var(n) =>
print(n)
case Fun(x, b) =>
print("^" + x + ".")
printTerm(b)
case App(f, v) =>
Console.print("(")
printTerm(f)
print(" ")
printTerm(v)
print(")")
} } def isIdentityFun(term: Term): Boolean = term match {
case Fun(x, Var(y)) if x == y => true
case _ => false } val id = Fun("x", Var("x")) val t = Fun("x", Fun("y", App(Var("x"), Var("y")))) printTerm(t) println println(isIdentityFun(id)) println(isIdentityFun(t)) }
To add something to my comment due to lack of available space: consider the following example case class:
case class My(x: Int)
If you save it to file and pass it to scalac -print, you get following expanded code (I removed unimportant stuff):
case class My extends Object with Product with Serializable {
<caseaccessor> <paramaccessor> private[this] val x: Int = _;
<stable> <caseaccessor> <accessor> <paramaccessor> def x(): Int = My.this.x;
Notice <caseaccessor>s here.
And then companion object:
<synthetic> object My extends runtime.AbstractFunction1 with Serializable {
case <synthetic> def apply(x: Int): My = new My(x);
case <synthetic> def unapply(x$0: My): Option = if (x$0.==(null))
scala.this.None
else
new Some(scala.Int.box(x$0.x()));
case <synthetic> <bridge> def apply(v1: Object): Object = My.this.apply(scala.Int.unbox(v1));
//...
Notice apply and unapply here. If you look at complete output yourself, you'll learn more about how scala generates your code.