Why Scala case class copy method parameterised only with the variables defined in the case class? - scala

Why Scala case class copy method parameterised only with the variables defined in the case class?
The question based on on the Q&A:
Case class copy does not maintain state of an inherited trait
Short summary - when trait is defined with a field and extended by a case class, copy on the case class will create the new class instance only with the variables defined in case class, without the extended trait.
trait A {
var list: List[Int] = List()
def add(element: Int) = {
list = element :: list
}
}
case class B(str: String) extends A {
val b = B("foo")
println("B1: " + b.list)
b.add(1)
b.add(2)
b.add(3)
println("B2: " + b.list)
val b2 = b.copy(str = "bar")
println("B3: " + b.list)
println("B4: " + b2.list)
}
Here, B4: () will be empty, while B3:(3,2,1)

Because there is no reasonable way to do what you want consistently.
For your example, generated code for copy could be
def copy(str: String = this.str, list: List[Int] = this.list): B = {
val newB = B(str)
newB.list = list
newB
}
Good enough. Now what happens if you change list to be private, or a val instead of a var? In both cases newB.list = ... won't compile, so what code should the compiler generate?

If you really want to keep the value of list after copying (considering the mutability issue I mentioned in the comments of OP), you can write your own copy method.
case class B(str: String) extends A {
def copy(str: String = this.str, list: List[Int] = this.list): B = {
val newB = B(str)
list.reverse.foreach(newB.add)
newB
}
}

Related

Scala - Using 'this' keyword multiple times one after the other will fail

I've come across an issue where using the this keyword in Scala multiple times within the same method will actually fail.
I cannot replicate the problem here because the codebase is too large, but I will do my best to show the problem.
I have a class, Foo, with an override-able method fooMethod. Inside fooMethod, three property values are generated, and the current class instance is updated with these properties separately, using this. However, only the last this call actually sets any of the properties, the two preceding this calls have no effect on the object.
case class Foo(prop1: prop, prop2: prop2, prop3:prop3) extends FooParent {
override def fooMethod(){
val propA = gen()
val propB = gen()
val propC = gen()
this.withPropA(propA)
this.withPropB(propB)
this.withPropC(propC)
}
def withPropA(:propA): Foo = this.copy(prop1 = propA)
def withPropB(:propB): Foo = this.copy(prop2 = propB)
def withPropC(:propC): Foo = this.copy(prop3 = propC)
}
The above code will only apply the final this.withPropC call, and therefore only prop3 is updated.
However, if I do the following
case class Foo(prop1: prop, prop2: prop2, prop3:prop3) extends FooParent {
override def fooMethod(){
val propA = gen()
val propB = gen()
val propC = gen()
// here
val one = this.withPropA(propA)
val two = one.withPropB(propB)
two.withPropC(propC)
}
def withPropA(:propA): Foo = this.copy(prop1 = propA)
def withPropB(:propB): Foo = this.copy(prop2 = propB)
def withPropC(:propC): Foo = this.copy(prop3 = propC)
}
then all of the properties are updated. Why is this?
Case class are immutable, so copy based functions (like those withProp*) never mutate this.
Moreover, in case of sequential property changes, each update must be applied on the result of previous one (chain); Not on (orginal) this, what would create separate instances corresponding to each unrelated update.
If you really intend to use such functions, it should be
withPropA(propA). // chain update
withPropB(propB). // chain
withPropC(propC)
What can be written:
copy(prop1 = propA, prop2 = propB, prop3 = propC)

Scala: How to define an enum with extra attributes?

I have a use-case where I need to define a new enum type LongShort but I need it in a way to also carry the sign so it can be directly used in mathematical expressions e.g.
object LongShortType extends Enumeration {
type Type = Value
val Long = Value(+1)
val Short = Value(-1)
}
I'd then like to use it like this:
val longShort = LongShortType.Short
val numberOfContracts: Int = 10
val vanillaOptionNotional: Double = longShort*numberOfContracts
but this leads to compiler error cannot resolve symbol * ... is there a way to extract the value of the enum? Or am I not understanding how enum types work?
The type of LongShortType.Short isn't Int, it's Value. You can either extract the underlying id of the value:
val longShort = LongShortType.Short.id
Which is a little ugly. Or you could not use an enum type at all:
object LongShortType {
val Long = 1
val Short = -1
}
And then your equation would work as is.
OK I worked out a solution to accomplish what I wanted without any compromisse and by that I mean that this solution has all the advantages of using Scala enum e.g. the withName and still allows me to define extra features on it:
object LongShortType extends Enumeration {
type Type = LongShortVal
val Long = Value("Long", +1)
val Short = Value("Short", -1)
case class LongShortVal(name: String, sign: Int) extends Val(nextId, name)
protected final def Value(name: String, sign: Int) = new LongShortVal(name, sign)
}
and now can do:
val longShort = LongShortType.Short
val numberOfContracts: Int = 10
val vanillaOptionNotional: Double = longShort.sign*numberOfContracts
and can also do:
val longShort = LongShort.withName("Long") // returns LongShort.Long

Unpacking tuple directly into class in scala

Scala gives the ability to unpack a tuple into multiple local variables when performing various operations, for example if I have some data
val infos = Array(("Matt", "Awesome"), ("Matt's Brother", "Just OK"))
then instead of doing something ugly like
infos.map{ person_info => person_info._1 + " is " + person_info._2 }
I can choose the much more elegant
infos.map{ case (person, status) => person + " is " + status }
One thing I've often wondered about is how to directly unpack the tuple into, say, the arguments to be used in a class constructor. I'm imagining something like this:
case class PersonInfo(person: String, status: String)
infos.map{ case (p: PersonInfo) => p.person + " is " + p.status }
or even better if PersonInfo has methods:
infos.map{ case (p: PersonInfo) => p.verboseStatus() }
But of course this doesn't work. Apologies if this has already been asked -- I haven't been able to find a direct answer -- is there a way to do this?
I believe you can get to the methods at least in Scala 2.11.x, also, if you haven't heard of it, you should checkout The Neophyte's Guide to Scala Part 1: Extractors.
The whole 16 part series is fantastic, but part 1 deals with case classes, pattern matching and extractors, which is what I think you are after.
Also, I get that java.lang.String complaint in IntelliJ as well, it defaults to that for reasons that are not entirely clear to me, I was able to work around it by explicitly setting the type in the typical "postfix style" i.e. _: String. There must be some way to work around that though.
object Demo {
case class Person(name: String, status: String) {
def verboseStatus() = s"The status of $name is $status"
}
val peeps = Array(("Matt", "Alive"), ("Soraya", "Dead"))
peeps.map {
case p # (_ :String, _ :String) => Person.tupled(p).verboseStatus()
}
}
UPDATE:
So after seeing a few of the other answers, I was curious if there was any performance differences between them. So I set up, what I think might be a reasonable test using an Array of 1,000,000 random string tuples and each implementation is run 100 times:
import scala.util.Random
object Demo extends App {
//Utility Code
def randomTuple(): (String, String) = {
val random = new Random
(random.nextString(5), random.nextString(5))
}
def timer[R](code: => R)(implicit runs: Int): Unit = {
var total = 0L
(1 to runs).foreach { i =>
val t0 = System.currentTimeMillis()
code
val t1 = System.currentTimeMillis()
total += (t1 - t0)
}
println(s"Time to perform code block ${total / runs}ms\n")
}
//Setup
case class Person(name: String, status: String) {
def verboseStatus() = s"$name is $status"
}
object PersonInfoU {
def unapply(x: (String, String)) = Some(Person(x._1, x._2))
}
val infos = Array.fill[(String, String)](1000000)(randomTuple)
//Timer
implicit val runs: Int = 100
println("Using two map operations")
timer {
infos.map(Person.tupled).map(_.verboseStatus)
}
println("Pattern matching and calling tupled")
timer {
infos.map {
case p # (_: String, _: String) => Person.tupled(p).verboseStatus()
}
}
println("Another pattern matching without tupled")
timer {
infos.map {
case (name, status) => Person(name, status).verboseStatus()
}
}
println("Using unapply in a companion object that takes a tuple parameter")
timer {
infos.map { case PersonInfoU(p) => p.name + " is " + p.status }
}
}
/*Results
Using two map operations
Time to perform code block 208ms
Pattern matching and calling tupled
Time to perform code block 130ms
Another pattern matching without tupled
Time to perform code block 130ms
WINNER
Using unapply in a companion object that takes a tuple parameter
Time to perform code block 69ms
*/
Assuming my test is sound, it seems the unapply in a companion-ish object was ~2x faster than the pattern matching, and pattern matching another ~1.5x faster than two maps. Each implementation probably has its use cases/limitations.
I'd appreciate if anyone sees anything glaringly dumb in my testing strategy to let me know about it (and sorry about that var). Thanks!
The extractor for a case class takes an instance of the case class and returns a tuple of its fields. You can write an extractor which does the opposite:
object PersonInfoU {
def unapply(x: (String, String)) = Some(PersonInfo(x._1, x._2))
}
infos.map { case PersonInfoU(p) => p.person + " is " + p.status }
You can use tuppled for case class
val infos = Array(("Matt", "Awesome"), ("Matt's Brother", "Just OK"))
infos.map(PersonInfo.tupled)
scala> infos: Array[(String, String)] = Array((Matt,Awesome), (Matt's Brother,Just OK))
scala> res1: Array[PersonInfo] = Array(PersonInfo(Matt,Awesome), PersonInfo(Matt's Brother,Just OK))
and then you can use PersonInfo how you need
You mean like this (scala 2.11.8):
scala> :paste
// Entering paste mode (ctrl-D to finish)
case class PersonInfo(p: String)
Seq(PersonInfo("foo")) map {
case p# PersonInfo(info) => s"info=$info / ${p.p}"
}
// Exiting paste mode, now interpreting.
defined class PersonInfo
res4: Seq[String] = List(info=foo / foo)
Methods won't be possible by the way.
Several answers can be combined to produce a final, unified approach:
val infos = Array(("Matt", "Awesome"), ("Matt's Brother", "Just OK"))
object Person{
case class Info(name: String, status: String){
def verboseStatus() = name + " is " + status
}
def unapply(x: (String, String)) = Some(Info(x._1, x._2))
}
infos.map{ case Person(p) => p.verboseStatus }
Of course in this small case it's overkill, but for more complex use cases this is the basic skeleton.

Scala Erasure Type Match and Use in Different Method

I have been searching around to achieve this, even with Manifest and Reflect API, it's still hard to achieve.
With Manifest and Reflection, I can match List[Any] to a class(List[A]), I am also able to get match by type T, just as in
http://daily-scala.blogspot.co.uk/2010/01/overcoming-type-erasure-in-matching-1.html
How save a TypeTag and then use it later to reattach the type to an Any (Scala 2.10)
but how can I make sure the type of the input and use it in a method?
Say,
object test {
val list : List[List[Any]] = List(
List(2.5, 3.6 ,7.9),
List("EUR","HKD", "USD")
)
def calculateString(in:List[String]) = {
println("It's a String List")
println(in)
}
def calculateDouble(in:List[String]) = {
println("It's a Double List")
println(in)
}
def main( args: Array[String]){
list.foreach(l=> matchAndCalculate(l))
}
// Copy from Andrzej Jozwik it doesn't work, but it's good to demonstrate the idea
def matchAndCalculate(list:List[Any]) = list match {
case i if i.headOption.exists(_.isInstanceOf[Long]) => calculateLong(i)
case i if i.headOption.exists(_.isInstanceOf[String]) => calculateString(i)
}
}
Many Thanks
Harvey
PS: As Sarah pointed out that it might be the only way that keeping type manifest while I create the list in the first before I put them into more complex structure.
Here's the challenge: is that possible to cast List[Any] back to / match to something say List[String] and as input to method like def dummyMethod(stringList: List[String]) without pissing off compiler?
Unless you can change your data structure, Andrej's solution is the only reasonable way to do this.
You can't really use type manifests, because you have two levels of indirection. You'd need a different type manifest for every member of the outer list. E.g., you could have a List[(List[Any], TypeTag[Any])], but there's no way to get compile-time information about every individual row out of a List unless you build that information at the time that you're constructing the lists.
If you really wanted to carry along static type information, it would be easy to do this with implicits and just make each entry in your outer list a special class.
One simple variant might look like this:
class CalculableList[A](val elements: List[A])(implicit val calc: Calculator[A]) {
def calculate = calc(elements)
}
trait Calculator[-A] extends (List[A] => Unit)
implicit object StringCalc extends Calculator[String] {
def apply(in: List[String]) {
println("It's a String List")
println(in)
}
}
implicit object DoubleCalc extends Calculator[Double] {
def apply(in: List[Double]) {
println("It's a Double List")
println(in)
}
}
val list: List[CalculableList[_]] = List(
new CalculableList(List(1.0, 2.0, 3.0)),
new CalculableList(List("a", "b", "c"))
)
list foreach { _.calculate }
Another option for this kind of generic programming is to use Miles Sabin's Shapeless. This uses special data structures to let you construct arbitrary-sized tuples that can be treated like type-safe lists. It generates a data structure similar to a linked list with a generic type wrapper that keeps track of the type of each row, so you wouldn't want to use it unless your lists are fairly short. It's also a bit difficult to learn, maintain and understand—but it opens up some deep wizardry when you understand and use it appropriately.
I don't know enough about your use case to know whether Shapeless is advisable in this case.
In Shapeless for Scala 2.11, a solution would look something like this:
import shapeless._
val lists = List(1.0, 2.0, 3.0) ::
List("a", "b", "c") ::
HNil
object calc extends Poly1 {
implicit def doubleList = at[List[Double]] { in =>
println("It's a double list")
println(in)
}
implicit def stringList = at[List[String]] { in =>
println("It's a string list")
println(in)
}
}
lists map calc
def calculateString(in:List[String]) = {
println("It's a String List")
println(in)
}
def calculateDouble(in:List[Double]){
println("It's a Double List")
println(in)
}
def castTo[T](t:T,list:List[Any]) = list.asInstanceOf[List[T]]
def matchAndCalculate(list:List[Any]) = list.headOption match {
case Some(x:Double) => calculateDouble(castTo(x,list))
case Some(x:String) => calculateString(castTo(x,list))
}
And check:
scala> matchAndCalculate(List(3.4))
It's a Double List
List(3.4)
scala> matchAndCalculate(List("3.4"))
It's a String List
List(3.4)
scala> val list : List[List[Any]] = List(
| List(2.5, 3.6 ,7.9),
| List("EUR","HKD", "USD")
| )
list: List[List[Any]] = List(List(2.5, 3.6, 7.9), List(EUR, HKD, USD))
scala> list.foreach(l=> matchAndCalculate(l))
It's a Double List
List(2.5, 3.6, 7.9)
It's a String List
List(EUR, HKD, USD)

Deep access of fields in Scala using runtime reflection

I have code that deeply walks a case class' constructor fields, which of course may themselves be complex (list of things, maps, options, and other case classes). The code I found to extract field values at runtime works great on the highest-level fields but explodes when I try to access deeper fields. Example below.
I real life my application introspects the fields at each level, so I know that 'stuff' is another case class (I have the Symbol/Type), and I know Dos' field Symbols/Types. But this is obtained at runtime so I think it's blowing up because it doesn't know [T]/Manifest[T]. Is there a way to get this at runtime via reflection? How might my code change? The examples I found seemed to all require various things[T], which I wouldn't have for 'dos', right?
case class Uno( name:String, age:Int, pets:List[String], stuff:Dos )
case class Dos( foo:String )
object Boom extends App {
val ru = scala.reflect.runtime.universe
val m = ru.runtimeMirror(getClass.getClassLoader)
val u = Uno("Marcus",19,List("fish","bird"),Dos("wow"))
println("NAME: "+unpack(u,"name")) // Works
println("PETS: "+unpack(u,"pets")) // Works
// ----- Goes Boom -------
val dos = unpack(u,"stuff")
println("Other: "+unpack(dos,"foo")) // Boom!
// -----------------------
// Get object value for named parameter of target
def unpack[T]( target:T, name:String )(implicit man:Manifest[T]) : Any = {
val im = m.reflect(target)
val fieldX = ru.typeOf[T].declaration(ru.newTermName(name)).asTerm.accessed.asTerm
im.reflectField(fieldX).get
}
}
You're exactly right, the type of your dos is Any.
FieldMirror.symbol.typeSignature is what you'd get from typeOf[Dos].
So consider returning a pair (Any, Type) from unpack to have something to pass to unpack(target, type, name). Somewhat like:
case class Uno(name: String, age: Int, pets: List[String], stuff: Dos)
case class Dos(foo: String)
object Boom extends App {
import scala.reflect.runtime.universe._
import scala.reflect.runtime.{ currentMirror => cm }
import scala.reflect.ClassTag
val u = Uno("Marcus", 19, List("fish", "bird"), Dos("wow"))
println("NAME: " + unpack(u, "name")) // Works
println("PETS: " + unpack(u, "pets")) // Works
// ----- Goes Boom -------
val (dos, dosT) = unpack(u, "stuff")
println("Other: " + unpack(dos, dosT, "foo")) // Boom! ...or fizzle
// -----------------------
def unpack[T: TypeTag](target: T, name: String): (Any, Type) = unpack(target, typeOf[T], name)
// Get object value for named parameter of target
def unpack[T](target: T, t: Type, name: String): (Any, Type) = {
val im = cm.reflect(target)(ClassTag(target.getClass))
val fieldX = t.declaration(newTermName(name)).asTerm.accessed.asTerm
val fm = im.reflectField(fieldX)
(fm.get, fm.symbol.typeSignature)
}
}