A few of case classes share a few common attributes and one functions using those common attributes. I would like to refactor them so that
the copy function can be used and one or more those attributes can
be altered with the function
those common functions only need to be defined once
I have tried to create a trait on the top of those case classes. This approach solves the second problem, but not the first one.
Any suggestions?
The closest you can get to what you want, without using reflection, is, probably, something like this:
trait Foo[T <: Foo[_]] {
def foo: String
def copyMe(foo: String): T
}
case class Bar(foo: String, bar: String) extends Foo[Bar] {
def copyMe(foo: String) = copy(foo=foo)
}
Related
Just a precursor, I'm coming from a Java background and am fairly new to Scala. As I develop more in Scala and try to become more FP oriented, I realize I can make almost all of my code: functions (and even methods?) contained in Objects (with a sprinkling of case classes where needed). In that case - is there any use at all for regular classes?
//traits (interfaces) without implementation are perfectly valid from FP standpoint
//it's just a bag of named functions
trait A {
def foo(s: String): Int
}
//Ok, you can implement a trait without declaring a class
object Obj extends A {
override def foo(s: String): Int = s.length
}
//But if you want your function to be parametrized then classes are useful
//You can think of classes as partially aplied functions in FP sense
class Clz(param: String) extends A {
override def foo(s: String): Int = (param + s).length
}
Say I've a base abstract class and 2 case classes extending it.
sealed abstract class Base extends Product with Serializable
case class A(d: String) extends Base
case class B(d: Int) extends Base
And I have also a type class on A and B, for example
trait Show[T] {
def show(t: T): String
}
object Show {
def apply[T](t: T)(implicit show: Show[T]): String = show.show(t)
implicit val showA: Show[A] = new Show[A] {
def show(t: A): String = "A"
}
implicit val showB: Show[B] = new Show[B] {
def show(t: B): String = "B"
}
}
The problem I have is that, in my code I get A and B from deserialization and they have type Base. In this case scala fail to resolve the typeclasses because there's not type classes defined on Base.
I could solve this problem by defining an instance on Base and do a pattern match but IMO in this way we'd better not use typeclasses at all.
Is there any tricks that we can make scala resolve type classes for a base class?
Thanks.
No, there is no such trick. Type has to be statically known because it is the compiler who resolves the typeclass instance.
As you said an instance for Base that will resolve proper instance has to be created. It can be done manually but there might be better ways to do it. Maybe someone can provide a better answer on how to do it nicely, but fundamentally the instance for Base is needed.
I wrote a basic Algebraic Data Type defined as follows
sealed trait Fruit {def name: String}
case class Apple(name: String) extends Fruit
case class Orange(name: String, color: String) extends Fruit
What I'd love to do is to define a common method across Apple and Orange. So I decided to offer this feature by a Type Class pattern.
sealed trait ServingFruit[T] {
def peel(fruit: T): String
}
object FruitManager {
def retrievePeelColor[T: ServingFruit](fruit: T): String =
implicitly[ServingFruit[T]].peel(fruit)
implicit object ApplePeelColor extends ServingFruit[Apple] {
def peel(fruit: Apple): String = "GREEN"
}
implicit object OrangePeelColor extends ServingFruit[Orange] {
def peel(fruit: Orange): String = fruit.color
}
}
For a necessary (and unfortunate) constraint I have to handle fruits as bounded instances of the shared base trait Fruit
def myCodeMethod[F <: Fruit](fruit: F, out: String) = {
import FruitManager._
FruitManager.retrievePeelColor(fruit)
}
And it brings me to the following (somehow expected) exception.
could not find implicit value for evidence parameter of type my.path.to.fruit.ServingFruit[F] [error]FruitManager.retrievePeelColor(fruit)
Then, AFAIU here and here Type Class Pattern is type independent and perhaps the latter is not well fitting my scenario.
The point is I'm struggling on figuring out a valuable solution to integrate my ADT with a common method available also to the base trait and - at the same time - I'd like to avoid providing the methods within the ADT (I'd try to stay FP oriented) and to use such workarounds as to add an additional Fruit converter to my Type Class.
Any help'd be really appreciated, thank you.
Andrea
You need to make the type class witness passed into retrievePeelColor as an implicit parameter:
scala> def retrievePeelColor[T](fruity: T)(implicit peeler: ServingFruit[T]) = peeler.peel(fruity)
retrievePeelColor: [T](fruity: T)(implicit peeler: ServingFruit[T])String
scala> retrievePeelColor(Apple("granny smith"))
res0: String = GREEN
scala> retrievePeelColor(Orange("bloody", "RED"))
res1: String = RED
And as for the design: I'm not an experienced design guy, but I wouldn't say that having some methods in a sealed trait isn't "FP style". If only fruits are peelable, and there are finitely many, it's OK to have one place for peel, IMHO (by this I'm talking about a method in Fruit matching on this, or a static member in the Fruit companion object).
Is there an easy way to get the values of all the variables in a case class without using reflection. I found out that reflection is slow and should not be used for repetitive tasks in large scale applications.
What I want to do is override the toString method such that it returns tab-separated values of all fields in the case class in the same order they've been defined in there.
What I want to do is override the toString method such that it returns tab-separated values of all fields in the case class in the same order they've been defined in there.
Like this?
trait TabbedToString {
_: Product =>
override def toString = productIterator.mkString(s"$productPrefix[", "\t", "]")
}
Edit: Explanation—We use a self-type here, you could also write this: Product => or self: Product =>. Unlike inheritance it just declares that this type (TabbedToString) must occur mixed into a Product, therefore we can call productIterator and productPrefix. All case classes automatically inherit the Product trait.
Use case:
case class Person(name: String, age: Int) extends TabbedToString
Person("Joe", 45).toString
You could use its extractor:
case class A(val i: Int, val c: String) {
override def toString = A.unapply(this).get.toString // TODO: apply proper formatting.
}
val a = A(5, "Hello world")
println(a.toString)
I have the following code:
trait Base[A,B] {
def name: String
}
trait BaseCompanion[A,B] {
def classOfBase: Class[_ <: Base[A,B]] // Can I implement something generic here ?
}
case class First(name: String) extends Base[Int,String]
object First extends BaseCompanion[Int,String] {
override def classOfBase: Class[_ <: Base[Int, String]] = classOf[First] // Can this part be generic ?
}
I don't want to override the classOfBase method in every concrete class that will extend BaseCompanion.This can be achieved by changing BaseCompanion to:
abstract class BaseCompanion[A,B, CLAZZ <: Base[A,B] : ClassTag] {
def classOfBase: Class[CLAZZ] = classTag[CLAZZ].runtimeClass.asInstanceOf[Class[CLAZZ]]
}
object First extends BaseCompanion[Int,String,First]
But I don't really like this solution, is there a way to do this without changing the signature of BaseCompanion and implement something generic inside the it ?
By the way today Companion object of any case class "defines" apply(...) method. Given the example above there will be a method similar to this:
abstract class BaseCompanion[A,B, CLAZZ <: Base[A,B] : ClassTag] {
def classOfBase: Class[CLAZZ] = classTag[CLAZZ].runtimeClass.asInstanceOf[Class[CLAZZ]]
/* No need to implement in the companion of a case class that extends Base */
def apply(name: String): Base[A,B]
}
The return type of this apply method is known to the Companion perhaps there is a way to use this information.
Yes, it can be done with this change:
def classOfBase = this.getClass.getMethods.find(_.getName == "apply").get.
getReturnType.asInstanceOf[Class[_ <: Base[A,B]]]
Note that this assumes there is precisely one apply method. In practice, you should check this assumption.
Assuming that if what you want would work, the following would be possible:
case class First(name: String) extends Base[Int, String]
object First extends BaseCompanion[Int, String]
assert(First.baseClass == classOf[First])
Now if that would work, what would stop you from doing the following?
class Second extends BaseCompanion[Int, String]
val second = new Second
println(second.baseClass)
or
// case class Third not defined
object Third extends BaseCompanion[Int, String]
println(Third.baseClass)
What would that result in? Second and Third are not a companion object with an associated class. Second is a class itself!
The problem is that you cannot force your BaseCompanion trait to only be inherited by something that is a companion object. BaseCompanion therefore cannot use the special relation that companion objects and associated classes have. If you want information about the associated class with a companion object, you have to give BaseCompanion that information manually in the definition of your companion object.
The Scala compiler won't allow you to do this. You can work around this with reflection if you want, but whatever solution remains that accomplishes this has to take into account that you are effectively creating unpredictable runtime behaviour. In my opinion, it's best to just help the compiler figure it out, and supply the proper information at compile time.