Functional literal distribution in Scala

I have a class that represents sales orders:

class SalesOrder(val f01:String, val f02:Int, ..., f50:Date)

fXX fields are of different types. I ran into the problem of creating an audit trail of my orders. Given two instances of the class, I have to determine which fields have been changed. I came up with the following:

 class SalesOrder(val f01:String, val f02:Int, ..., val f50:Date){ def auditDifferences(that:SalesOrder): List[String] = { def diff[A](fieldName:String, getField: SalesOrder => A) = if(getField(this) != getField(that)) Some(fieldName) else None val diffList = diff("f01", _.f01) :: diff("f02", _.f02) :: ... :: diff("f50", _.f50) :: Nil diffList.flatten } } 

I was wondering what the compiler does with all _.fXX functions: they are instantiated only once (statically) and can be shared by all instances of my class, or will they be displayed every time I create an instance of my class?

My concern is that since I will be using multiple instances of SalesOrder, this can create a lot of garbage. Should I use a different approach?

+4
source share
2 answers

One clean way to solve this problem is to use the standard Ordering type class library. For instance:

 class SalesOrder(val f01: String, val f02: Int, val f03: Char) { def diff(that: SalesOrder) = SalesOrder.fieldOrderings.collect { case (name, ord) if !ord.equiv(this, that) => name } } object SalesOrder { val fieldOrderings: List[(String, Ordering[SalesOrder])] = List( "f01" -> Ordering.by(_.f01), "f02" -> Ordering.by(_.f02), "f03" -> Ordering.by(_.f03) ) } 

And then:

 scala> val orderA = new SalesOrder("a", 1, 'a') orderA: SalesOrder = SalesOrder@5827384f scala> val orderB = new SalesOrder("b", 1, 'b') orderB: SalesOrder = SalesOrder@3bf2e1c7 scala> orderA diff orderB res0: List[String] = List(f01, f03) 

You almost certainly don't need to worry about the performance of your original formulation, but this version is (possibly) better for unrelated reasons.

+2
source

Yes, it creates 50 short-lived functions. I donโ€™t think you should worry if you donโ€™t have obvious evidence that this causes performance problems in your case.

But I would define a method that converts SalesOrder to Map[String, Any] , then you just have

 trait SalesOrder { def fields: Map[String, Any] } def diff(a: SalesOrder, b: SalesOrder): Iterable[String] = { val af = a.fields val bf = b.fields af.collect { case (key, value) if bf(key) != value => key } } 

If field names are really just incremental numbers, you can simplify

 trait SalesOrder { def fields: Iterable[Any] } def diff(a: SalesOrder, b: SalesOrder): Iterable[String] = (a.fields zip b.fields).zipWithIndex.collect { case ((av, bv), idx) if av != bv => f"f${idx + 1}%02d" } 
+1
source

Source: https://habr.com/ru/post/1488990/


All Articles