Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do I have to create a new object to mix in a Scala trait?

Tags:

scala

traits

In Scala, calling groupBy() on a collection returns a Map where the values are collections, but I want a MultiMap. What's the easiest way to do the conversion? Can I avoid creating a new MultiMap and copying everything over?

like image 1000
Craig P. Motlin Avatar asked Nov 27 '09 19:11

Craig P. Motlin


People also ask

Can we create object of trait in Scala?

Traits are similar in spirit to interfaces in Java programming language. Unlike a class, Scala traits cannot be instantiated and have no arguments or parameters. However, you can inherit (extend) them using classes and objects.

How do you create an object for a trait?

Defining a Trait for Common Behavior We create a trait object by specifying some sort of pointer, such as a & reference or a Box<T> smart pointer, then the dyn keyword, and then specifying the relevant trait.

How do you implement a trait in Scala?

In scala, trait is a collection of abstract and non-abstract methods. You can create trait that can have all abstract methods or some abstract and some non-abstract methods. A variable that is declared either by using val or var keyword in a trait get internally implemented in the class that implements the trait.

What is a mixin in Scala?

Mixins are traits which are used to compose a class. Scala 2.


1 Answers

I think the answer to "Do I have to create a new object to mix in a Scala trait?" is "Yes". You can minimize the pain some with wrapping objects and implicit conversions.


For your specific problem, I was unable to coerce groupBy(...) to return a mutable map to mutable sets, which you would need to wrap it with "MapProxy with MultiMap". But, it is not too many lines of code to implement your own version of "groupBy":

package blevins.example

object App extends Application {

  implicit def multiMapable[B](c: Iterable[B]) = new {
    def groupByMM[A](f: B => A) = {
      import scala.collection.mutable._
      val ret = new HashMap[A,Set[B]] with MultiMap[A,B]
      for (e <- c) { ret.addBinding(f(e), e) }
      ret
    } 
  }

  val c = List(1,2,3,4,5,6,7,8,9)
  val mm = c.groupByMM { i => if (i < 5) "alpha" else "beta" }
  mm.addBinding("alpha",12)
  println(mm) // Map(beta -> Set(5, 7, 6, 9, 8), alpha -> Set(3, 1, 4, 2, 12))

}

Addendum

Here is an example of wrapping an existing Map[String,Set[Int]] into a MultiMap without copying the values:

object App extends Application {
  import scala.collection.mutable._
  val seed: Map[String,Set[Int]] = Map("even" -> Set(2,4,6), "odd" -> Set(1,3,5))

  val multiMap = new MapProxy[String,Set[Int]] with MultiMap[String,Int] {
    val self = seed
  }

  multiMap.addBinding("even", 8)
  println(multiMap) // Map(odd -> Set(5, 3, 1), even -> Set(6, 8, 4, 2))
}

Note that this cannot be done on the result of groupBy(...) because the seed map is required to be mutable and groupBy(...) returns an immutable map.

like image 70
Mitch Blevins Avatar answered Nov 11 '22 19:11

Mitch Blevins