Scala change parameters of function defined in trait - scala

Because I didn't find a solution to my problem anywhere, I think I might be thinking into a very wrong direction.
Here's my problem:
I have a trait A and another trait B and companion objects AB1, AB2, AB3 and so on. The singleton objects extend trait A and the classes extend trait B. Many objects of those classes are in a list.
On these objects I want to use functions defined in the corresponding singleton object which take objects of the same class as the singleton object is.
This an example for the traits:
trait A {
def compare(firstB: B, secondB: B) : Int
}
trait B {}
And the companion objects:
class AB1(val variable: Int) extends B {}
object AB1 extends A {
def apply(list: List[Int]): Option[AB1] = {
if(list.foldLeft(0)(_ + _) < 10 && list.nonEmpty)
some(new AB1(list.head))
else
null
}
override def compare(ab11: AB1, ab12: AB1): Int = {
if(ab11 > ab12)
1
else if(ab11 > ab12)
-1
else
0
}
}
and
class AB2(val variable1: Int, val variable2: Int) extends B {}
object AB2 extends A {
def apply(list: List[Int]): Option[AB1] = {
if(list.foldLeft(0)(_ + _) < 20 && list.length >= 2)
some(new AB1(list.head, list.tail.head))
else
null
}
override def compare(ab21: AB2, ab22: AB2): Int = {
if(ab11 > ab12)
10
else if(ab11 > ab12)
-10
else
0
}
}
So I've already filtered the some objects and put the "real" objects into a list, let's call it bList. On every element of the list I want to call the compare function.
I think it would look something like this:
val bList: List[B]
val a = getA(bList.head) // getA should be a function that returns the companion object of a class
a.compare(bList.head, bList.tail.head)
On my way I encountered two problems:
b.getClass does not equal AB1.getClass when b is an object the class AB1. But this is not my main problem. I found a solution using String comparison, which really is not pretty, but for now, it works.
The compare function has to be defined in the trait, because otherwise it can't be casted on any singleton object that extends trait A. But I find no way to define the function with parameters of a variable type.
I really hope you can help me with this problem!
EDIT: Now I see that I've forgotten to mention something:
I think that I have to go a bit deeper into what I am trying to do to make you understand my problem:
I have a List[List[C]]. A List of those C's may be capable of creating an AB1 object with it but maybe AB2, or maybe AB3 and so on. So I have
val c: List[C] = (C1, C2, C4)
val aList: List[A] = (AB1, AB2, AB3, ...)
val bestB: B = (for{
element <- aList
} yield element (c)).flatten.head // Because the List aList is ordered: AB1 is the best case, AB2 the second best and so on.
I do that for every List[C] out of the List[List[C]]. So in the end I may have a List[B] = (AB3, AB1, AB2, AB1) (for example). From this list I want to get the "best" Bs according to the order of aList at first - then i get List[B] = (AB1, AB1). These two AB1's I want to compare and then put the "better" Element (according to the compare function of the corresponding object) or both into a new list. This is want I want to accomplish.

To be honest, I'm still confused with what is your root problem. But I will try to answer what I understood.
First, if you want to change the type of the arguments when overriding a function from a trait. Then, the answer is you can't! - Because that would break the Liskov Substitution Principle.
But you can achieve what you want with a Type Class .
trait B {}
trait BComparator[Bi <: B] {
def compare(firstB: Bi, secondB: Bi): Int
}
Now if you want a way to dynamically obtain the right instance of the BComparator for your sub-classes you could make those instances as implicit values in their companion objects.
class B1 extends B {}
object B1 {
implicit val B1Comparator: BComparator[B1] = new BComparator[B1] {
override def compare(firstB: B1, secondB: B2): Int = ???
}
}
Now, given b11 and b12 as instances of B1 you could just write
implicitly[BComparator[B1]].compare(b11, b12)

I think you need to use implicit Comparator:
trait B
case class AB1(variable: Int) extends B
case class AB2(variable1: Int, variable2: Int) extends B
implicit object AB1Comparator extends Comparator[AB1] {
override def compare(o1: AB1, o2: AB1): Int = java.lang.Integer.compare(o1.variable, o2.variable)
}
implicit object AB2Comparator extends Comparator[AB2] {
override def compare(o1: AB2, o2: AB2): Int = java.lang.Integer.compare(o1.variable1, o2.variable1) match {
case 0 => java.lang.Integer.compare(o1.variable2, o2.variable2)
case other => other
}
}
def compare[A](obj1: A, obj2: A)(implicit comparator: Comparator[A]) = {
comparator.compare(obj1, obj2)
}
val ab1List = List(AB1(1), AB1(2), AB1(3))
val ab1Compare = compare(ab1List.head, ab1List.tail.head)
val ab2List = List(AB2(1, 1), AB2(1, 1), AB2(1, 3))
val ab2Compare = compare(ab2List.head, ab2List.tail.head)
Or if you want to sort list you should use Ordering:
trait B
case class AB1(variable: Int) extends B
implicit object AB1Ordering extends Ordering[AB1] {
override def compare(o1: AB1, o2: AB1): Int = java.lang.Integer.compare(o1.variable, o2.variable)
}
val ab1List = List(AB1(1), AB1(2), AB1(3))
val ab1ListSorted = ab1List.sorted

Related

Scala generic class design

So I have the following scenario. First a class hierarchy A <- B <- C
trait A
trait B extends A
class C extends B
I also have a class that has a generic parameter defined as [T <: A]
class Foo[T <: A]
This class defines two methods that accept objects of type T
def single(t: T): Bar
def multiple(lt: List[T]): Bars
If the objects t and lt are of a type derived from B both, of these methods call another method that takes t and lt (mapping over its elements), does some modification to it (which depends on the type itself) and spits the same object out
def update[P <: B](op: P, item: Item): P = {
if (item.field1..) op.field1 = item.field1
if (item.field2..) op.field2 = item.field2
...
op match {
case c: C =>
if (item.field123 ...) c.field123 = item.field123
}
op
}
I don't like the way this method is right now as it does mutation on the objects. As I am following a functional programming style I have managed to keep the codebase immutable and composable.
I would prefer to push the field assignments to constructors and build up the objects based on their parent class but due to Scala's auxiliary constructor calling scheme I cannot find a way to do this. Another way would have been to have a case class and use the copy constructor but I cannot do that because I need to keep A, B and C extendable.
I hope I managed to describe my scenario well enough. If you need some more clarification - please ask. I would appreciate any help with this one.
Typeclasses to the rescue
object Example {
trait Item
// generic interface that makes possible for T
// to be updated by an Item
// Better to return a new object here instead of mutating an old one
trait Updater[T] {
def update(obj: T, item: Item): T
}
class B1
class B2
implicit val b1Updated: Updater[B1] = new Updater[B1] {
override def update(obj: B1, item: Item): B1 = {
println("B1 updater called")
//your code for b1 here
???
}
}
implicit val b2Updated: Updater[B2] = new Updater[B2] {
override def update(obj: B2, item: Item): B2 = {
println("B2 updater called")
//your code for b2 here
???
}
}
//whenever you add a new class that has to be updatable you must provide such instance of Updater[MyNewB]
//But you don't have to declare it right here so it's still modular
//works for every type T that has implicit instance of type Updater[T]
def updateOne[T: Updater](obj: T, item: Item): T = {
implicitly[Updater[T]].update(obj, item)
}
def updateList[T: Updater](lst: List[T], item: Item): List[T] = {
val updater = implicitly[Updater[T]]
lst.map(e => updater.update(e, item))
}
def main(args: Array[String]): Unit = {
val list: List[B1] = List(new B1, new B1)
updateList(list, new Item {})
}
}

Override implicit vals from trait

I need overriding implicit in object res defing one from trait. The purpose is to define custom implicits in one place (trait B). Trait a is defined in external library. Is it possible?
trait t {
}
object m extends t
object q extends t
trait a {
implicit val o: t = m
}
trait b {
implicit val o: t = q
}
trait c {
def action(implicit v: t): Unit = {}
}
object res extends c with a with b {
//i need smth like override val o = super[b].o
val ololo= action
}
It is not possible to mix-in two unrelated traits that both contain a member with the same identifier. The Scala compiler has no way to resolve which one would take precedence in this scenario. Since types A and B are related, o does not even need to have the same type in both of them. Trait B needs to extend A and override o. There isn't any other way to override a member without using inheritance.
trait T
case object M extends T
case object Q extends T
trait A {
implicit val o: T = M
}
trait B extends A {
override implicit val o: T = Q
}
trait C {
def action(implicit v: T): Unit = println(v)
}
object Res extends C with B {
def call() = action
}
scala> Res.call()
Q
Since you are already mixing A into Res anyway, it is assumed that A is not difficult to extend, since Res must implement any other unmentioned abstract members.

Accessing members of mixin traits

I have the following code in scala:
trait A {
val foo: String => Int = { in =>
in.toInt
}
}
trait B extends A {
def bar(a: String) = {
foo(a)
}
}
class C(a: String) {
self: B =>
val b = bar(a)
}
val x = new C("34") with B
During instantiation of x I get NPE. Couldn't figure out why.
edit
NOTE: Can not figure out why foo of A trait doesn't get initialized
Please refer to the http://docs.scala-lang.org/tutorials/FAQ/initialization-order.html.
The only addition to this is that self-type makes class C abstract. So actually you do:
abstract class C(a: String) {
def bar(a: String): Int
val b = bar(a)
}
val x = new C("34") with B
You can try to replace it in your code and see same result. Some more info here.
In short: the linearization of new C with B will be (B <- A) <- C, so initalization is C -> (A -> B). Please refer to Class Initialization section section:
After the superclass constructor is executed, the constructors for each mixin trait are executed. Since they are executed in right-to-left order within the linearization, but the linearization is created by reversing the order of the traits, this means the constructors for the mixin traits are executed in the order that they appear in the declaration for the class. Remember, however, that when mixins share hierarchy, the order of execution may not be quite the same as how the mixins appear in the declaration.
In your case new C("34") with B equals to class K extends C("34") with B; new K. Note that self type of class C doesn't affect the initialization order.
Simplified example:
scala> trait C {def aa: String; println(s"C:$aa")}
defined trait C
scala> trait D {val aa = "aa"; println(s"D:$aa")}
defined trait D
scala> new C with D
C:null
D:aa
res19: C with D = $anon$1#2b740b6
Solution: If your foo is placed in third party library (so you can't make it lazy), you may just use mix-in instead of self-type or at least mix A into the C class:
trait A {
val foo: String => Int = { in =>
in.toInt
}
}
trait B extends A {
def bar(a: String) = {
foo(a)
}
}
class C(a: String) extends A {
self: B =>
val b = bar(a)
}
val x = new C("34") with B
The short answer on why you get a NullPointerException is, that initialization of C requires initializing b, which invokes the method stored in val foo, which is not initialized at this point.
Question is, why is foo not initialized at this point? Unfortunately, I cannot fully answer this question, but I'd like to show you some experiments:
If you change the signature of C to extends B, then B, as the superclass of C is instantiated before, leading to no exception being thrown.
In fact
trait A {
val initA = {
println("initializing A")
}
}
trait B extends A {
val initB = {
println("initializing B")
}
}
class C(a: String) {
self: B => // I imagine this as C has-a B
val initC = {
println("initializing C")
}
}
object Main {
def main(args: Array[String]): Unit ={
val x = new C("34") with B
}
}
prints
initializing C
initializing A
initializing B
while
trait A {
val initA = {
println("initializing A")
}
}
trait B extends A {
val initB = {
println("initializing B")
}
}
class C(a: String) extends B { // C is-a B: The constructor of B is invoked before
val initC = {
println("initializing C")
}
}
object Main {
def main(args: Array[String]): Unit ={
val x = new C("34") with B
}
}
prints
initializing A
initializing B
initializing C
As you can see, the initialization order is different. I imagine the dependency-injection self: B => to be something like a dynamic import (i.e., putting the fields of an instance of B into the scope of C) with a composition of B (i.e., C has-a B). I cannot prove that it is solved like this, but when stepping through with IntelliJ's debugger, the fields of B are not listed under this while still being in the scope.
This should answer the question on why you get a NPE, but leaves the question open on why the mixin is not instantiated first. I cannot think of problems that may occur otherwise (since extending the trait does this basically), so this may very well be either a design choice, or noone thought about this use case. Fortunately, this will only yield problems during instantiation, so the best "solution" is probably to not use mixed-in values during instantiation (i.e., constructors and val/var members).
Edit: Using lazy val is also fine, so you can also define lazy val initC = {initB}, because lazy val are not executed until they are needed. However, if you do not care about side effects or performance, I would prefer def to lazy val, because there is less "magic" behind it.
Declare A.foo to be a lazy val.

Elegant way to sort Array[B] for a subclass B < A, when A extends Ordered[A]?

Having defined a class A which extends Ordering[A], and a subclass B of A, how do I automatically sort an Array of Bs? The Scala compiler complains that it "could not find implicit value for parameter ord: Ordering[B]". Here's a concrete REPL example (Scala 2.8), with A = Score and B = CommentedScore:
class Score(val value: Double) extends Ordered[Score] {
def compare(that: Score) = value.compare(that.value)
}
defined class Score
trait Comment { def comment: String }
defined trait Comment
class CommentedScore(value: Double, val comment: String) extends Score(value) with Comment
defined class CommentedScore
val s = new CommentedScore(10,"great")
s: CommentedScore = CommentedScore#842f23
val t = new CommentedScore(0,"mediocre")
t: CommentedScore = CommentedScore#dc2bbe
val commentedScores = Array(s,t)
commentedScores: Array[CommentedScore] = Array(CommentedScore#b3f01d, CommentedScore#4f3c89)
util.Sorting.quickSort(commentedScores)
error: could not find implicit value for parameter ord: Ordering[CommentedScore]
util.Sorting.quickSort(commentedScores)
^
How do I fix this (that is, sort an Array[B] = Array[CommentedScore] "for free", given that I know how to sort Array[A] = Array[Score]), in an elegant manner which avoids boilerplate?
Thanks!
Add the required implicit yourself:
implicit val csOrd: Ordering[CommentedScore] = Ordering.by(_.value)
You can put this in a CommentedScore companion object so that there is no boilerplate at use-site.
Edit: if you want the ordering method to be defined only at the top of the inheritance tree, you still have to provide an Ordering for each subclass, but you can define the compare method of the Ordering in terms of the one in the Score object. i.e.
object Score {
implicit val ord: Ordering[Score] = Ordering.by(_.value)
}
object CommentedScore {
implicit val csOrd = new Ordering[CommentedScore] {
def compare(x: CommentedScore, y: CommentedScore) = Score.ord.compare(x, y)
}
}
if you don't want to re-define this for each sub-class, you can use a generic method to produce the Ordering:
object Score {
implicit def ord[T <: Score]: Ordering[T] = Ordering.by(_.value)
}
This is a bit less efficient since being a def rather than a val, it creates a new Ordering each time one is required. However the overhead is probably tiny. Also note, the Ordered trait and compare method is not necessary now we have Orderings.
You might use Order from scalaz, which is contravariant, so you need not to define it for every subclass. Here is an example:
import scalaz._
import Scalaz._
class Score(val value: Double)
object Score {
implicit val scoreOrd: Order[Score] = orderBy(_.value)
}
trait Comment { def comment: String }
class CommentedScore(value: Double, val comment: String) extends Score(value) with Comment {
override def toString = s"cs($value, $comment)"
}
def quickSort[E: Order](list: List[E]): List[E] = list match {
case Nil => Nil
case head :: tail =>
val (less, more) = tail partition { e => implicitly[Order[E]].order(e, head) == LT }
quickSort(less) ::: head :: quickSort(more)
}
println(quickSort(List(
new CommentedScore(10,"great"),
new CommentedScore(5,"ok"),
new CommentedScore(8,"nice"),
new CommentedScore(0,"mediocre")
))) // List(cs(0.0, mediocre), cs(5.0, ok), cs(8.0, nice), cs(10.0, great))
This works:
val scoreArray: Array[Score] = Array(s, t)
util.Sorting.quickSort(scoreArray)
Or if you are starting from the Array[CommentedScore]:
val scoreArray: Array[Score] = commentedScores.map(identity)
util.Sorting.quickSort(scoreArray)
Note you can sort more simply with:
scoreArray.sorted

Automatically Hash Consed Case Classes

I'm looking for a way to have classes that behave just like case classes, but that are automatically hash consed.
One way to achieve this for integer lists would be:
import scala.collection.mutable.{Map=>MutableMap}
sealed abstract class List
class Cons(val head: Int, val tail: List) extends List
case object Nil extends List
object Cons {
val cache : MutableMap[(Int,List),Cons] = MutableMap.empty
def apply(head : Int, tail : List) = cache.getOrElse((head,tail), {
val newCons = new Cons(head, tail)
cache((head,tail)) = newCons
newCons
})
def unapply(lst : List) : Option[(Int,List)] = {
if (lst != null && lst.isInstanceOf[Cons]) {
val asCons = lst.asInstanceOf[Cons]
Some((asCons.head, asCons.tail))
} else None
}
}
And, for instance, while
scala> (5 :: 4 :: scala.Nil) eq (5 :: 4 :: scala.Nil)
resN: Boolean = false
we get
scala> Cons(5, Cons(4, Nil)) eq Cons(5, Cons(4, Nil))
resN: Boolean = true
Now what I'm looking for is a generic way to achieve this (or something very similar). Ideally, I don't want to have to type much more than:
class Cons(val head : Int, val tail : List) extends List with HashConsed2[Int,List]
(or similar). Can someone come up with some type system voodoo to help me, or will I have to wait for the macro language to be available?
You can define a few InternableN[Arg1, Arg2, ..., ResultType] traits for N being the number of arguments to apply(): Internable1[A,Z], Internable2[A,B,Z], etc. These traits define the cache itself, the intern() method and the apply method we want to hijack.
We'll have to define a trait (or an abstract class) to assure your InternableN traits that there is indeed an apply method to be overriden, let's call it Applyable.
trait Applyable1[A, Z] {
def apply(a: A): Z
}
trait Internable1[A, Z] extends Applyable1[A, Z] {
private[this] val cache = WeakHashMap[(A), Z]()
private[this] def intern(args: (A))(builder: => Z) = {
cache.getOrElse(args, {
val newObj = builder
cache(args) = newObj
newObj
})
}
abstract override def apply(arg: A) = {
println("Internable1: hijacking apply")
intern(arg) { super.apply(arg) }
}
}
The companion object of your class will have to be a mixin of a concrete class implementing ApplyableN with InternableN. It would not work to have apply directly defined in your companion object.
// class with one apply arg
abstract class SomeClassCompanion extends Applyable1[Int, SomeClass] {
def apply(value: Int): SomeClass = {
println("original apply")
new SomeClass(value)
}
}
class SomeClass(val value: Int)
object SomeClass extends SomeClassCompanion with Internable1[Int, SomeClass]
One good thing about this is that the original apply need not be modified to cater for interning. It only creates instances and is only called when they need to be created.
The whole thing can (and should) also be defined for classes with more than one argument. For the two-argument case:
trait Applyable2[A, B, Z] {
def apply(a: A, b: B): Z
}
trait Internable2[A, B, Z] extends Applyable2[A, B, Z] {
private[this] val cache = WeakHashMap[(A, B), Z]()
private[this] def intern(args: (A, B))(builder: => Z) = {
cache.getOrElse(args, {
val newObj = builder
cache(args) = newObj
newObj
})
}
abstract override def apply(a: A, b: B) = {
println("Internable2: hijacking apply")
intern((a, b)) { super.apply(a, b) }
}
}
// class with two apply arg
abstract class AnotherClassCompanion extends Applyable2[String, String, AnotherClass] {
def apply(one: String, two: String): AnotherClass = {
println("original apply")
new AnotherClass(one, two)
}
}
class AnotherClass(val one: String, val two: String)
object AnotherClass extends AnotherClassCompanion with Internable2[String, String, AnotherClass]
The interaction shows that the Internables' apply method executes prior to the original apply() which gets executed only if needed.
scala> import SomeClass._
import SomeClass._
scala> SomeClass(1)
Internable1: hijacking apply
original apply
res0: SomeClass = SomeClass#2e239525
scala> import AnotherClass._
import AnotherClass._
scala> AnotherClass("earthling", "greetings")
Internable2: hijacking apply
original apply
res1: AnotherClass = AnotherClass#329b5c95
scala> AnotherClass("earthling", "greetings")
Internable2: hijacking apply
res2: AnotherClass = AnotherClass#329b5c95
I chose to use a WeakHashMap so that the interning cache does not prevent garbage collection of interned instances once they're no longer referenced elsewhere.
Code neatly available as a Github gist.
Maybe a little hacky, but you could try defining your own intern() method, like Java's String has:
import scala.collection.mutable.{Map=>MutableMap}
object HashConsed {
val cache: MutableMap[(Class[_],Int), HashConsed] = MutableMap.empty
}
trait HashConsed {
def intern(): HashConsed =
HashConsed.cache.getOrElse((getClass, hashCode), {
HashConsed.cache((getClass, hashCode)) = this
this
})
}
case class Foo(bar: Int, baz: String) extends HashConsed
val foo1 = Foo(1, "one").intern()
val foo2 = Foo(1, "one").intern()
println(foo1 == foo2) // true
println(foo1 eq foo2) // true