Last active
December 29, 2016 20:11
-
-
Save asieira/274a9e72a6ed11eb1335f9d5f6af7fee to your computer and use it in GitHub Desktop.
Generic implementation of instance interning (de-duplication) in Scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This trait defines the mechanism by which the global repository (pool) of objects | |
// is obtained for each type. | |
trait Interning[T] { | |
def repository: java.util.Map[T, T] | |
def intern(orig: T): T = { | |
val retval = repository.putIfAbsent(orig, orig) | |
if (retval == null) orig | |
else retval | |
} | |
} | |
object Interning { | |
// Handy implementation that creates a synchronized weak hash map for a type. | |
def repository[T]: java.util.Map[T, T] = | |
java.util.Collections.synchronizedMap[T, T](new java.util.WeakHashMap[T, T]) | |
// Convenience method to allow types that don't extend Internable to be interned. | |
def apply[T : Interning](orig : T) = implicitly[Interning[T]].intern(orig) | |
} | |
// This is supposed to be used as a mixin for classes that will support interning. | |
trait Internable[T] { | |
def intern(implicit interning: Interning[T]): T = interning.intern(this.asInstanceOf[T]) | |
} | |
// Example usage with a test class | |
case class Test(a: String) extends Internable[Test] | |
implicit object InterningTest extends Interning[Test] { | |
// it's critical to use a val and not a def here so that all Test instances | |
// are using the same repository for interning | |
override val repository = Interning.repository[Test] | |
} | |
// We can also use this with an existing type such as List[Int] | |
implicit object InterningListInt extends Interning[List[Int]] { | |
override val repository = Interning.repository[List[Int]] | |
} | |
object main { | |
def main(args: Array[String]) = { | |
// interning our own class | |
val a1 = new Test("a") | |
val a2 = new Test("a") | |
println(a1 eq a2) // False | |
println(a1.intern eq a2.intern) // True | |
// interning List[Int] | |
val l1 = List(1, 2, 3) | |
val l2 = List(1, 2, 3) | |
println(l1 eq l2) // False | |
println(Interning(l1) eq Interning(l2)) // True | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
An exercise in Scala features such as implicits and traits. The idea here was to try to generalize what String.intern does for any class in Scala.
The use of
asInstanceOf
inInternable
is a risk, but I couldn't find a better way of making this work while still keeping the return type of theintern
method equal toT
. Suggestions on a better approach are most welcome.