Automatically Hash Consed Case Classes - scala

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

Related

Scala change parameters of function defined in trait

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

Scala case class inheritance with code reusability

I am trying to model my class hierarchy in case classes. I appreciate related discussion about duplication of case class properties here.
Consider the class hierarchy shown below.
trait Super {
def a:String
}
case class Child1(a:String, b:String) extends Super {
override def toString = s" a = $a, b= $b"
}
case class Child2(a:String, c:String) extends Super {
override def toString = s" a = $a, c= $c"
}
I have a scenario where I want to construct case class objects using basic properties like a, b, c as well as using XML. I created companion objects for these case classes as below.
object Child1 {
def apply(node: scala.xml.Node): Child1 = {
val a = (node \ "a").text
val b = (node \ "b").text
Child1(a, b)
}
}
object Child2 {
def apply(node: scala.xml.Node): Child2 = {
val a = (node \ "a").text
val c = (node \ "c").text
Child2(a, c)
}
}
In above code, I have to duplicate the line that parses value of a - (node \ "a").text. There doesn't seem to be a way to do the same even if I convert Super to an abstract superclass.
I wonder how one can do this, which I could have done very easily using abstract class and couple of constructors in Super class in Java.
UPDATE: Qualified name for scala.xml.Node type.
Indeed this is not possible with a case class. You will have to define a helper to get rid of the duplication like this.
Child1(Super.getAValue(node), c)
This is a trivial task for scala.macros or shapeless
Lets define generic xml extractor
import scala.xml.Node
trait Extract[L] extends (scala.xml.Node => L)
And it's simple implementation for string-only containing HList records:
import shapeless._
import shapeless.labelled._
implicit object extractHNil extends Extract[HNil] {
def apply(node: Node): HNil = HNil
}
implicit def extractHCons[K <: Symbol, L <: HList]
(implicit witness: Witness.Aux[K], recur: Extract[L]) =
new Extract[FieldType[K, String] :: L] {
def apply(node: Node): ::[FieldType[K, String], L] = {
val name = witness.value.name
val value = (node \ name).text
field[K](value) :: recur(node)
}
}
Now you can construct case class extractor build on top of LabelledGeneric:
implicit def extractCase[C, L]
(implicit lgen: LabelledGeneric.Aux[C, L], extract: Extract[L]) =
new Extract[C] {
def apply(node: Node): C = lgen.from(extract(node))
}
From this point you can add simple mixin for your companions:
abstract trait XmlReader[C] {
def extract: Extract[C]
def apply(node: scala.xml.Node) = extract(node)
}
And implement your builders as
object Child1 extends XmlReader[Child1] {
val extract: Extract[Child1] = implicitly
}
object Child2 extends XmlReader[Child2] {
val extract: Extract[Child2] = implicitly
}
Now you can verify it:
val node = <node>
<a>1</a>
<b>2</b>
<c>3</c>
</node>
println(Child1(node)) // a = 1, b= 2
println(Child2(node)) // a = 1, c= 3
Note that it's not very hard task to extend such parsers for work with nearly anything defined via sealed families of case classes. See picopickle as example of generic parser built with shapeless
define a method superA do it
import scala.reflect.runtime.universe._
trait Super {
def a: String
}
trait Node {
def \(s: String): String = s
}
object Node {
// also you can move it to Super companion object
implicit class SuperMethodA(val node: Node) {
def superA = node \ "a"
}
}
case class Child1(a: String, b: String) extends Super {
override def toString = s" a = $a, b= $b"
}
object Child1{
def apply(node: Node): Child1 = {
val a = node.superA //.text
val b = (node \ "b") //.text
Child1(a, b)
}
}
case class Child2(a: String, c: String) extends Super {
override def toString = s" a = $a, c= $c"
}
object Child2{
def apply(node: Node): Child2 = {
val a = node.superA //.text
val c = (node \ "c") //.text
Child2(a, c)
}
}

Scala - handling "multiple overloaded alternatives of method ... define default arguments"

Let's say I have a setting such as this:
sealed trait Annotation {
def notes : Seq[String]
}
trait Something extends Annotation{
//do something funny
}
case class A(val i:Int)(val notes:Seq[String] = Nil) extends Something
object A{
def apply(a:A)(notes:Seq[String] = Nil):A = A(a.i)(notes)
}
case class B(val b:Boolean)(val notes:Seq[String] = Nil) extends Something
object B{
def apply(b:B)(notes:Seq[String] = Nil):B = B(b.b)(notes)
}
case class C(val s:String)(val notes:Seq[String] = Nil) extends Something
object C{
def apply(c:C)(notes:Seq[String] = Nil) :C = C(c.s)(notes)
}
Trying to compile this will result in
Main.scala:10: error: in object A, multiple overloaded alternatives of method apply define
default arguments.
object A{
^
Main.scala:15: error: in object B, multiple overloaded alternatives of method apply define
default arguments.
object B{
^
Main.scala:20: error: in object C, multiple overloaded alternatives of method apply define
default arguments.
object C{
^
three errors found
I have read this, so I do at least have an idea as to why this is happening, what I don't know, however, is how I am supposed to resolve the issue.
One possibility would - of course - be to simply omit the default values and force the client to provide Nil when no notes are to be stored, but is there a better solution?
My first guess was to simply make the default arguments explicit:
case class A(i: Int)(val notes: Seq[String]) extends Something
object A {
def apply(i: Int): A = new A(i)(Nil)
def apply(a: A)(notes: Seq[String]): A = new A(a.i)(notes)
def apply(a: A): A = new A(a.i)(Nil)
}
However, now, because of currying, you just have a function Int => A and Int => Seq[String] => A (and analogous for A => A) with the same name in scope.
If you refrain from currying you can manually define the overloaded methods:
case class B(b: Boolean, notes: Seq[String]) extends Something
object B {
def apply(b: Boolean): B = B(b, Nil)
def apply(b: B, notes: Seq[String] = Nil): B = B(b.b, notes)
}
But, since notes is now part of the same parameter list as b, the behavior of the case-class methods such as toString is changed.
println(B(true)) // B(true,List())
println(B(true, List("hello"))) // B(true,List(hello))
println(B(B(false))) // B(false,List())
Finally, to mimic the original behavior more closely, you can implement your own equals, hashCode, toString, and unapply methods:
class C(val s:String, val notes:Seq[String] = Nil) extends Something {
override def toString = s"C($s)"
override def equals(o: Any) = o match {
case C(`s`) => true
case _ => false
}
override def hashCode = s.hashCode
}
object C{
def apply(s: String, notes: Seq[String]) = new C(s, notes)
def apply(s: String): C = C(s, Nil)
def apply(c:C, notes:Seq[String] = Nil): C = C(c.s, notes)
def unapply(c: C): Option[String] = Some(c.s)
}
Example:
val c1 = C("hello")
val c2 = C("hello", List("world"))
println(c1) // C(hello)
println(c2) // C(hello)
println(c1 == c2) // true
c1 match { // hello
case C(n) => println(n)
case _ =>
}

Scala: Polymorphic daisy chaining

class Foo(protected[this] val s: Iterator[String]) {
def apply(it: Iterator[String]): Foo = new Foo(it ++ s)
}
class Bar(s: Iterator[String]) extends Foo(s) {
}
Question: How can I get Bar.apply() to return a new Bar instead of a new Foo? I don't want to override.
You can use F-bounded polymorphism to get an apply that returns the proper type. You also need to define a method that creates an instance of the subclass:
abstract class Foo[X](protected[this] val s: Iterator[String]) {
self: X =>
def newSubclass(s: Iterator[String]): X
def apply(it: Iterator[String]): X = newSubclass(it ++ s)
}
class Bar(s: Iterator[String]) extends Foo[Bar](s) {
def newSubclass(s: Iterator[String]): Bar = new Bar(s)
}
Bar.apply will have Bar as its return type, without needing to be overriden.
You can read more about F-bounded polymorphism at the Twitter Scala school.
Have looked through this article. Seems it's what you want. Quickly scetch out simple example(using var's in this example)
class A(var s: String) {
def apply(a: String): this.type = {
s = "A" + a
this
}
}
class B(var s: String) extends A(s)
P.S.: Tried to use vals but it is impposible to call constructor in method which return type is this.type. Maybe you'll find the solution))

Scala: Do implicit conversions work on Any?

I would like to store some objects from different type hierarchy into List[Any] or similar container, but perform implicit conversions on them later on to do something like type class.
Here is an example:
abstract class Price[A] {
def price(a: A): Int
}
trait Car
case class Prius(year: Int) extends Car
trait Food
case class FriedChicken() extends Food
object Def {
// implicit object AnyPrices extends Price[Any] {
// def price(any: Any) = 0
// }
// implicit object PriusPrices extends Price[Prius] {
// def price(car: Prius) = 100
// }
implicit object CarPrices extends Price[Car] {
def price(car: Car) = 100
}
implicit object FoodPrices extends Price[Food] {
def price(food: Food) = 5
}
}
def implicitPrice[A: Price](x: A) = implicitly[Price[A]].price(x)
import Def._
val stuff: List[Any] = List(Prius(2010), FriedChicken())
stuff map { implicitPrice(_) }
The above code throws an error as follows:
error: could not find implicit value for evidence parameter of type Price[Any]
stuff map { implicitPrice(_) }
^
If you uncomment AnyPrices, you'd get List(0,0), but that's not what I am expecting.
Do I have to store the manifest into the list for this to work?
Also, List(Prius(2010)) map { implicitPrice(_) } doesn't work either because it wants Price[Prius] and Price[Car] isn't good enough. Is there a way to make it more flexible?
So, looks like I can't get a type class once the objects are reduced to Any. My attempt of using Manifest also failed, since there seems to be no way for me to cast an Any into T even if I have the Manifest[T] object.
import reflect.Manifest._
def add [A, B >: A](stuff: A, list: List[(B, Manifest[_])])(implicit m: Manifest[A]) = (stuff, m) :: list
val stuff2 = add(Prius(2000), add(FriedChicken(), Nil))
stuff2 map { x =>
val casted = x._2.erasure.cast(x._1)
implicitPrice(casted)
}
gives me
error: could not find implicit value for evidence parameter of type Price[Any]
so it seems like I have to resolve things into Price before I stick them into List:
abstract class Price[A] {
def price(a: Any): Int
}
trait Car
case class Prius(year: Int) extends Car
trait Food
case class FriedChicken() extends Food
object Def {
implicit object PriusPrices extends Price[Prius] {
def price(car: Any) = 100
}
implicit object FriedChickenPrices extends Price[FriedChicken] {
def price(food: Any) = 5
}
}
import Def._
def add [A, B >: A](stuff: A, list: List[(B, Price[_])])(implicit p: Price[A]) = (stuff, p) :: list
val stuff = add(Prius(2000), add(FriedChicken(), Nil))
stuff map { x => x._2.price(x._1) }