I have a hierarchy like the following:
case class A(val a: Long, val b: String)
case class B(val c: String) extends A(a=3, b="a string")
and I'm trying to serialize it using lift-json ala the following:
val obj = B(c="another string")
val cameraJson = net.liftweb.json.Serialization.write(obj)
but what I'm seeing is that it only serializes the properties in class B and not those in A.
I've also tried:
compact(render(decompose(obj)))
with the same result
What gives? Is there something obvious in Scala that I'm missing?
case class inheritance is a deprecated feature of Scala. This should work for instance:
trait A { val a: Long; val b: String }
case class B(a: Long = 3, b: String = "a string", c: String) extends A
val obj = B(c="another string")
var ser = Serialization.write(obj)
Serialization.read[B](ser)
Classic lift JSON serialisation for case classes is based on constructor argument list (see decompose implementation), not class attributes. So you have to either override all fields declared in the parent trait (as in the #Joni answer) or use composition instead of inheritance.
For example:
case class A(a: Long, b: String)
case class B(c: String, a: A = A(a=3, b="a string"))
B(c="another string")
BTW val keyword in case class constructor is unnecessary. The accessors for every constructor arg is one of the things you are getting for free by declaring class as a case.
IMO serializing only c seems like the right thing to do. The info appearing in serialization will be that the type is B and the value of C. Values of a and b are implied by the info type is B. They are 3 and "a string", and can be nothing else, so they do not need to be written.
From maybe too cursory a look at the source code, the default behavior of is to serialize fields that correspond to parameters of the primary constructor
Related
I'm brand new to shapeless and I would like to transform a Mapper[mix.type, HNil]#Out to a case class
How can I do this? (Let me know if you need more infos...)
That would only work if you define a case class that has the exact same shape that this Mapper#Out. If that's the case, you can create an instance of your case class using shapeless.Generic:
val mout = ... // HList coming from your Mapper
case class A(i: Int, s: String)
shapeless.Generic[A].from(mout): A
That's assuming Generic#Repr and Mapper[mix.type, HNil]#Out are the same type, which you can check using the following:
val mapper = the[Mapper[mix]]
val gen = the[Generic[A]]
implicitly[mapper#Out =:= gen#Repr] // This only complies if scalac can
// prove equality between these types
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'm using Scala 2.10.2, and have two case classes that have identical fields:
case class Foo(id: String, name: String)
case class Bar(id: String, name: String)
I'd like to do something like this:
case class Thing(id: String, name: String)
type Foo = Thing
type Bar = Thing
This compiles, but when I try to create a Foo, I get:
scala> Bar("a", "b")
<console>:8: error: not found: value Bar
Bar("a", "b")
^
Does type aliasing not work with case classes?
When you create a case class Scala automatically creates a companion object for it. In your code you define an alias for the type Thing, i.e. for the class Thing only. Your companion object Thing still has only 1 name and no aliases.
One way to "fix" it is to create a reference to the companion object (not a type alias) like this:
scala> val Bar = Thing
Bar: Thing.type = Thing
scala> Bar("a", "b")
res1: Thing = Thing(a,b)
Another way to "fix" it would be to rename the imported object with import package.{Thing => Bar}.
Type aliases only alias the type, not any companion object that might be supplying factory methods (whether you write that factory method yourself or get one "for free" from the compiler).
On the other hand, importing acts on names and if there are multiple entities associated with a given name, importing that name brings in every referent of the imported name. Additionally, you can rename when importing and you can do so multiply, so...
scala> object Stuff { case class Thing(id: String, name: String) }
defined module Stuff
scala> import Stuff.Thing
import Stuff.Thing
scala> import Stuff.{Thing => Foo}
import Stuff.{Thing=>Foo}
scala> import Stuff.{Thing => Bar}
import Stuff.{Thing=>Bar}
scala> val thing1 = Thing("fing", "fang")
thing1: Stuff.Thing = Thing(fing,fang)
scala> val foo1 = Foo("yes", "no")
foo1: Stuff.Thing = Thing(yes,no)
scala> val bar1 = Bar("true", "false")
bar1: Stuff.Thing = Thing(true,false)
It's no good for the rendering via toString, though, as you can see.
case class Thing(id: String, name: String)
type Foo = Thing
type Bar = Thing
if you say new Bar("a","b") it will work
Do you want Foo and Bar to be distinguishable (as when they are different case classes) or not? If yes, and you just want to avoid repeating list of fields, you can do this:
case class Foo(thing: Thing)
case class Bar(thing: Thing)
But this will obviously make them a bit less convenient to use in pattern matching or access fields. Field access can be improved a bit:
trait ThingWrapper {
def thing: Thing
def id = thing.id
def name = thing.name
}
case class Foo(thing: Thing) extends ThingWrapper
case class Bar(thing: Thing) extends ThingWrapper
I have a Scala case class that has certain val's as parameters. I have a couple of methods that makes use of this case class. Assuming that my case class is defined as follows:
case class CaseA(a: Int, b: List[CaseB])
case class CaseB(a: Int, b: text, c: Boolean)
Both the CaseA and CaseB represent the domain model of my case classes. But as I use them in my application, I want to add some behavior to CaseA based on CaseB's Boolean field. For example., let us suppose that in CaseA, the val b has 4 CaseB objects. I want to add a behavior that would run through b and tell me if any one of the element in CaseB has the val c set to true.
What I did come up is with the following implementation of CaseA:
case class CaseA(a: Int, b: List[CaseB], c: Boolean)
But the problem with this approach is that when I load my CaseA object from the database, I do not need to have the val c as the val c is computed and not part of CaseA object. I went a step further and modified my CaseA to look like as below:
case class CaseA(a: Int, b: List[CaseB], c: Option[Boolean])
I can see that it is already getting ugly. How can I add behavior to my case classes so that the val c need not be part of the CaseA object and it is rather computed everytime at runtime?
I would use a lazy value in case you don't need the c for all elements
case class CaseB(a:Int,b:String,c:Boolean)
case class CaseA(a:Int,b:List[CaseB]){
lazy val c = b exists (_.c)
}
val ca = CaseA(42, List(
CaseB(1,"hello",false),
CaseB(2,",",false),
CaseB(3,"world",true))
)
println(ca.c)
To answer some of your comment questions, if you want to use a mixin-trait, you can do something like the following:
case class CaseB(a:Int,b:String,c:Boolean)
case class CaseA(a:Int,b:List[CaseB])
trait CanCheck extends CaseA{
lazy val c = b exists (_.c)
}
val ca = new CaseA(42, List(
CaseB(1,"hello",false),
CaseB(2,",",false),
CaseB(3,"world",true))
) with CanCheck
println(ca.c)
Notice that you need to use the new keyword to make this work
In a two ways:
1) define c as a val, or even better, as a def:
case class CaseA(a: Int, b: List[CaseB]){
val c = b.exists(_.c)
}
2) use implicit wrappers:
case class CaseA(a: Int, b: List[CaseB])
implicit class CaseAC(underlying: CaseA) {
val c = underlying.b.exists(_.c)
}
val x = CaseA(3, Nil)
// x: CaseA = CaseA(3,List())
x.c
// Boolean = false
If you don't need to store c, you might use implicit value classes, which are even thinner wrapper
I don't understand what you are doing with a database. Ignoring that bit, I'd do the following:
case class CaseA(a: Int, b: List[CaseB]){
val c = b.exists(_.c)
}
I have two case classes that inherit from an abstract base class. I want to define some methods on the abstract base class that use the copy methods on the inheriting case classes (and so return an instance of the child class.) Is there a way to do this using self types?
Example code:
abstract class BaseClass(a: String, b: Int) {
this: case class => //not legal, but I'm looking for something similar
def doubleB(newB: Int) = this.copy(b = b * 2) //doesn't work because BaseClass has no copy
}
case class HasC(a: String, b: Int, c: Boolean) extends BaseClass(a, b) {
def doesStuffWithC(newC: Boolean) = {
...
}
}
case class HasD(a: String, b: Int, D: Double) extends BaseClass(a, b) {
def doesStuffWithD(newD: Double) = {
...
}
}
I've figured out how to get the result I want thanks to this question:
How to use Scala's this typing, abstract types, etc. to implement a Self type?
but it involves adding a makeCopy method to BaseClass and overriding it with a call to copy in each of the child case classes, and the syntax (especially for the Self type) is fairly confusing. Is there a way to do this with Scala's built in self typing?
You can't do what you want because copy needs to know about all the possible parameters. So even if case classes inherited from Copyable, it wouldn't be the copy you needed. Also, if you're going to keep the types straight, you'll be thwarted by Scala's lack of a "MyType". So you can't just extend a base class. However, you could add an abstract method and type annotation:
abstract class BaseClass[C <: BaseClass[_]](a: String, b: Int) {
def setB(b0: Int): C
def doubleB(b0: Int) = setB(b0*2)
}
case class HasC(a: String, b: Int, c: Boolean) extends BaseClass[HasC](a,b) {
def setB(b0: Int) = this.copy(b = b0)
def doesStuffWithC(c0: Boolean) = doubleB(if (c0) b else -b).copy(c = c0)
}
And then you can:
scala> HasC("fish",1,false).doesStuffWithC(true)
res47: HasC = HasC(fish,2,true)
This extra work will be worth it if you have a lot of shared functionality that depends on the ability to copy just b (either many methods, or a small number of complicated methods)--that is, this solves the DRY issue. If instead you want to abstract over HasC and other derived classes, you can either use BaseClass[_] or add yet another level that defines setB(b0: Int): BaseBase or simply forget the type parameterization and use BaseClass as the return type (but recognize that HasC cannot use BaseClass methods and still retain its type identity).
I think you're out of luck. The copy methods on HasC and HasD have different signatures. It's a bit hidden because of the default arguments, but basically the definition in BaseClass wouldn't know which copy method to call.
You could define a makeCopy in the abstract class that takes a copier function that takes Unit and returns a BaseClass, then, in your methods that use it (like doubleB) override them in the case class bodies and make use of makeCopy by passing it an anonymous function that does the work of creating a new copy with the props changed, like so:
package delegatedcopy
abstract class BaseClass(a: String, b:Int){
def aField = a
def bField = b
def doubleB:BaseClass
def makeCopy(copier: () => BaseClass):BaseClass = copier()
}
case class HasC(override val aField: String, override val bField: Int, cField: Boolean) extends BaseClass(aField, bField){
override def doubleB:BaseClass = makeCopy( ()=> HasC(aField, bField * 2, cField) )
}
case class HasD(override val aField: String, override val bField: Int, dField:Double) extends BaseClass(aField, bField){
override def doubleB:BaseClass = makeCopy( ()=> HasD(aField, bField * 2, dField) )
}
A test app that demonstrates it:
import delegatedcopy._
object TestApp extends Application{
val hasC = HasC( "A C object", 5, true)
val hasD = HasD( "A D object", 2, 3.55)
val hasCDoubleB = hasC.doubleB
val hasDDoubleB = hasD.doubleB
println(hasC) // prints HasC(A C object,5,true)
println(hasCDoubleB) //prints HasC(A C object,10,true)
println( hasD ) // prints HasD(A D object,2,3.55)
println( hasDDoubleB ) // prints HasD(A D object,4,3.55)
}
In this way, you are able to keep the makeCopy method the same for all children classes as in the base class, and can probably implement or mix in quite a bit of functionality in the base and case classes while keeping common code in a safe place and being able to pass clients a BaseClass and pattern match on the specific case classes.