Map of elements with variable generics - scala

There's this question for Java How to declare a map with variable generics?
I have the exact same problem.
Is there a better/Scala way of solving it?
EDIT:
I tried following the above answer, but without implementing an internal map.
private class SectionConversionMap
extends HashMap[SectionSchema[_], (Iterable[HtmlRow]) => Option[Iterable[_]]]
{
override def +[T, B1 >: ( Iterable[HtmlRow] ) =>
Option[Iterable[T]]](kv: (SectionSchema[T], B1)):
HashMap[SectionSchema[_], B1] = {
val m = super.+(kv)
m
}
}
But my IDE keeps insisting that
Expression of type HashMap[SectionSchema[_], Any] doesn't conform to expected type HashMap[SectionSchema[_], B1]

Don't extend standard collection types, it's just asking for trouble unless you know very well what you are doing. In this case the compiler will ensure all method signatures are at least as general as before, and your + isn't (note that in Binzi Cao's answer it doesn't override anything!). Just follow the source and keep the Map in a field.

Here is a simple example, maybe it can give you some hint:
import scala.collection.mutable._
class MyMap extends HashMap[Any, List[Any]] {
def put[T, B <% T](key: T, value: List[B]) = {
this += key -> value
}
}
val b = new MyMap()
b.put("q", List("q"))
b.put(12, List(12))
b.put(122, List("23")) //not compile
The last line will not compile:
No implicit view available from String => Int.
It seems you want to ovrride the standard scala lib function, however, I guess, you could not change the method return types if you want to do a override. The below is the scala Map Method
#migration("`+` creates a new map. Use `+=` to add an element to this map and return that map itself.", "2.8.0")
def + [B1 >: B] (kv: (A, B1)): Map[A, B1] = clone().asInstanceOf[Map[A, B1]] += kv
I did something similar in your code and it can compile now, hopefully it is what you needed or give you some clue:
import scala.collection.mutable._
type HtmlRow = String
type SectionSchema[T] = List[T]
private class SectionConversionMap extends HashMap[SectionSchema[_], (Iterable[_]) => Option[Iterable[_]]] {
def +[T, B1 >: ( Iterable[HtmlRow] ) => Option[Iterable[T]]](kv: (SectionSchema[T], B1)):
HashMap[SectionSchema[_], B1] = {
val m = clone().asInstanceOf[HashMap[SectionSchema[_], B1]]
m+=kv
}
}

Related

Why isn't Scala picking the most specific instance in this this type class?

I am struggling to build this computation pipeline builder in Scala. I want a class that has two methods, map and reduce, that receive anonymous functions in a "fluent interface". These functions will be composed, so I want to type-check all of them, also having their input type inferred from the previous method call... See this related question of mine (it's all part of the puzzle).
All my questions oversimplify the problem, but answers have been helpful, and I think I am almost arriving there.
I have managed to make everything work as long as I have as special method that I use when I register a mapper function that has a KeyVal output. But I wanted to use the same map name for the functions, and to simplify the architecture in general too. For that I decided to try using the type class pattern. That allows me to do different things depending on the type from the function in the argument of my builder method. Keep in mind too that part of my problem is that if I give to the mapper method a function that outputs a KeyVal[K,V] type (pretty much a tuple), and I need to store this K and V as type parameters from my builder class, so they can be used to type-check / infer the type from the reducer method later on.
This is my builder class
case class PipelineBuilder[A, V](commandSequence: List[MRBuildCommand]) {
trait Foo[XA, XB, +XV] {
def constructPB(xs: XA => XB): PipelineBuilder[XB, XV]
}
implicit def fooAny[XA, XB]: Foo[XA, XB, Nothing] = new Foo[XA, XB, Nothing] {
def constructPB(ff: XA => XB) = PipelineBuilder[XB, Nothing](MapBuildCommand(ff) :: commandSequence)
}
implicit def fooKV[XA, XK, XV]: Foo[XA, KeyVal[XK,XV], XV] = new Foo[XA, KeyVal[XK,XV], XV] {
def constructPB(ff: XA => KeyVal[XK,XV]) = PipelineBuilder[KeyVal[XK,XV], XV](MapBuildCommand(ff) :: commandSequence)
}
def innermymap[AA, FB, FV](ff: AA => FB)(implicit mapper: Foo[AA, FB, FV]) = mapper.constructPB(ff)
def mymap[FB](ff: A => FB) = innermymap(ff)
def rreduce[K](newFun: (V, V) => V)(implicit ev: KeyVal[K, V] =:= A) =
PipelineBuilder[A,V](RedBuildCommand[K, V](newFun) :: commandSequence)
def output(dest: MRWorker) = constructPipeline(dest)
//...
}
And this is how the class is used in the main program
object PipelineLab extends App {
val mapredPipeline = PipelineBuilder[String, Nothing](List())
.mymap { s: String => s.toLowerCase }
.mymap { s: String => KeyVal(s, 1) }
.rreduce(_ + _)
.output(OutputWorker)
// ...
}
Note that the s: String shouldn't be necessary because if the type parameter A from the class. Same goes for V in the rreduce.
I have already managed to use the type class pattern in the following simple example. If I output a tuple of something, it does something different... Here it is.
object TypeClassLab extends App {
trait FuncAdapter[A, B] {
def runfunc(x: A, f: A => B): B
}
implicit def myfunplain[X, A]: FuncAdapter[X, A] = new FuncAdapter[X, A] {
def runfunc(x: X, f: X => A): A = {
println("Function of something to plain, non-tuple type")
f(x)
}
}
implicit def myfuntuple[X, AA, AB]: FuncAdapter[X, (AA, AB)] = new FuncAdapter[X, (AA, AB)] {
def runfunc(x: X, f: X => (AA, AB)): (AA, AB) = {
println("Function from String to tuple")
f(x)
}
}
def ffuunn[A, B](x: A)(f: A => B)(implicit fa: FuncAdapter[A, B]) = {
fa.runfunc(x, f)
}
println(ffuunn("obaoba") { s => s.length })
println(ffuunn("obaobaobaobaoba") { s => s.length })
println(ffuunn("obaoba") { s => (s.length, s.reverse) })
println(ffuunn("obaobaobaobaoba") { s => (s.length, s.reverse) })
}
//OUTPUT:
//Function of something to plain, non-tuple type
//6
//Function of something to plain, non-tuple type
//15
//Function from String to tuple
//(6,aboabo)
//Function from String to tuple
//(15,aboaboaboaboabo)
Works like a charm. But then I can't adapt it to my real problem... Right now it seems the compiler is not looking for the more specific fooKV implicit, and instead always picks fooAny, and that causes an error when I try to run rreduce, because it is expecting a V <: Nothing. How do I make it work?
I'm not sure I fully understand your question.
As far as choosing fooAny vs fooKV, the instance of Foo must be known and passed appropriately from the site where the types are known. This would be the place where mymap is called. Foo is not passed as a parameter though.
def mymap[FB](ff: A => FB) = innermymap(ff)
You are requiring it be know when innermymap(ff) is called. At this point, type information is lost. The only available instance of Foo is fooAny.
This is actually an example of why a definition like fooAny should not exist. You are defining a valid relationship between any XA and any XB, even if these are in fact just Any. The existence of this definition is causing your code to type check when it should not. This will most likely happen again.

Shapeless: Checking Type Constraints of Polymorphic functions

I'm working on a small library for economic models that check the Units of the entities, using Types, e.g. instead of val apples = 2.0 we write val apples = GoodsAmount[KG, Apples](2.0). For creating bundle of goods, I trying to use HLists from the shapeless library. This works fine, but in some cases I can not be as generic code as I prefer. See e.g. the following problem.
I start with a simple code that explain what I want to lift into shapeless. We create two classes, on that represent Km, the other Miles. It should be allowed to add Km classes, but not miles. That I use a abstract type T is mainly motivated be our more complex library. And the indirect call to the '+' function is just because we need something similar in the shapeless case behind.
trait Foo {
type T
val v: Double
def +[B <: Foo](other: B)(implicit ev: this.T =:= other.T) = v + other.v
}
trait _Km
trait _Miles
case class Km(v: Double) extends Foo { type T = _Km }
case class Miles(v: Double) extends Foo { type T = _Miles }
object ExampleSimple extends App {
def add[A <: Foo, B <: Foo](a: A, b: B)(implicit ev: a.T =:= b.T) = { a + b }
add(Km(1), Km(2))
// add(Km(1), Miles(2)) /* does not compile as intended */
}
This works as intended. But it's necessary to have the Type Contraint check on the 'add' function. My attempt to extend this to HLists looks like this:
object ExampleShapeless extends App {
import shapeless._
val l1 = Km(1) :: Km(2) :: HNil
val l2 = Km(4) :: Km(3) :: HNil
object add extends Poly1 {
implicit def caseTuple[A <: Foo] = at[(A,A)] { case (a, b) => a + b }
}
(l1 zip l2).map(add)
}
But this generate the following error message (using Scala 2.10.2):
[error] /home/fuerst/gitg3m/code/types/src/main/scala/lagom_d/extract.scala:50: Cannot prove that a.T =:= b.T.
[error] implicit def caseTuple[A <: Foo] = at[(A,A)] { case (a: Foo, b) => a + b }
[error] ^
[error] /home/fuerst/gitg3m/code/types/src/main/scala/lagom_d/extract.scala:54: could not find implicit value for parameter mapper: shapeless.Mapper[ExampleShapeless.add.type,shapeless.::[(Km, Km),shapeless.::[(Km, Km),shapeless.HNil]]]
[error] (l1 zip l2).map(add)
The first error should be fixed, in the case that I could add a Type Constraint to the caseTuple function, but to be honest, I have not understood how the at function is working and where I could add the implicit evidence parameter. And I'm also don't know, what I must do, so that the Mapper would find his implicit value.
A less generic version, where I replase the caseTuple function with
implicit def caseTuple = at[(Km,Km)] { case (a, b) => a + b }
works fine, but would need to write a lot of redundant code (okay, this solution would be still better as our current solution using Tuples). Can somebody give me a hint how I can solve this problem?
Thanks,
Klinke
You can require the type members to match by adding a type parameter to the case:
object add extends Poly1 {
implicit def caseTuple[_T, A <: Foo { type T = _T }] = at[(A, A)] {
case (a, b) => a + b
}
}
Or you could use an existential type, since you only really care that they're the same:
object add extends Poly1 {
implicit def caseTuple[A <: Foo { type T = _T } forSome { type _T }] =
at[(A, A)] {
case (a, b) => a + b
}
}
Either version will provide the behavior you want.

F-Bounded Polymorphism in Scala

I am using Scala 2.10-RC5
Here is my code:
object Fbound {
abstract class E[A <: E[A]] {
self: A =>
def move(a: A): Int
}
class A extends E[A] {
override def toString = "A"
def move(a: A) = 1
}
class B extends E[B] {
override def toString = "B"
def move(b: B) = 2
}
def main(args: Array[String]): Unit = {
val a = new A
val b = new B
val l = List(a, b)
val t = l.map(item => item.move(null.asInstanceOf[Nothing]))
println(t)
}
}
when run the program, exception occurs:
Exception in thread "main" java.lang.NullPointerException
at fb.Fbound$$anonfun$1.apply(Fbound.scala:20)
at fb.Fbound$$anonfun$1.apply(Fbound.scala:20)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
at scala.collection.immutable.List.foreach(List.scala:309)
at scala.collection.TraversableLike$class.map(TraversableLike.scala:244)
at scala.collection.AbstractTraversable.map(Traversable.scala:105)
at fb.Fbound$.main(Fbound.scala:20)
at fb.Fbound.main(Fbound.scala)
my question is:
Why it pass the compiler but fail at runtime?
Adding a line at the bottom - val t1 = l.map(item => item.move(item)) will fail the compiler, why?
Your code with null.asInstanceOf[Nothing] compiles because Nothing is a subclass of everything and, as such, complies with the required type for move. Needless to say, it will throw an exception at runtime.
When you try to compile the second line you gave, you are given something in the lines of this error:
<console>:19: error: type mismatch;
found : E[_6(in value $anonfun)] where type _6(in value $anonfun) >: B with A
<: E[_ >: B with A <: Object]
required: <root>._6
When you put the two instances in the same List, you have lost important information about the type of their elements. The compiler can't ensure that an element of type T >: B with A <: E[_ >: B with A] can be passed to the move method of an object of the same type, the same way that you can't do:
val c: E[_ >: B with A] = new A
val d: E[_ >: B with A] = new B
c.move(d) // note: the _ in c and d declarations are different types!
I don't know enough about self-types to be completely sure of this explanation, but it seems to me that it is a class-level restriction, and not an instance-level one. In other words, if you lose the information about the type parameter in E, you can't expect the compiler to know about the move argument particular type.
For instance-level restrictions, you have this.type. If you define move as:
def move(a: this.type): Int
Your code compiles, but I don't think it is what you want, as move will accept only the same instance you are calling it on, which is useless.
I can't think of any way you may enforce that restriction the way you want. I suggest you try to do that with type variables (i.e. defining a type variable type T = A in class E), which have, as far as I know, some degree of binding to instances. Perhaps you can explain in more detail your specific situation?
Re: second question
The problem is type of the argument of move method, I can't see it being possible to make it work if it is in any way tied to subclass(es), instead:
l has to be 'some form' of list of E-s
so then item will be 'some form' of E
type of argument to move has to have the same type
This is then the only way I could make it work with type arguments (changing btw name of type argument to X, not to be confused with name of class A, and removing self type declaration, which I think is irrelevant for this problem/discussion):
abstract class E[X <: E[X]]
{
def move (a: E[_]): Int
}
class A extends E[A]
{
def move(a: E[_]): Int = 1
}
class B extends E[B]
{
def move(b: E[_]): Int = 2
}
...
{
val a = new A
val b = new B
val l = List (a, b)
val t = l.map (item => item.move(item))
...
}
If someone could give a more 'type-restrictive' solution, I would really like to see it.
Another option, as Rui has suggested, would be to use a type member, something like this:
abstract class E
{
type C <: E
def move (x: E): Int
}
class A extends E
{
type C = A
def move(x: E): Int = 1
}
class B extends E
{
type C = B
def move(x: E): Int = 2
}
...
{
val a = new A
val b = new B
val l = List (a, b)
val t = l.map (item => item.move(item))
...
}

How to subclass Scala immutable.Map with fixed type parameters?

I can't figure out how to deal with overriding "+" in an immutable map if the map can only store an invariant type for its values.
Something like:
class FixedMap(val impl : Map[String, Int])
extends immutable.Map[String, Int] with immutable.MapLike[String, Int, FixedMap] {
// This should return FixedMap if B1 is Int, and Map[String,B1]
// if B1 is a superclass of Int; but there's no way to do that.
// It is possible to return FixedMap here but then you have to
// throw at runtime if B1 is not Int
override def +[B1 >: Int](kv : (String, B1)) : Map[String, B1] = {
kv match {
case (k, v : Int) =>
new FixedMap(impl + Pair(k, v))
case _ =>
impl + kv
}
}
// ...
}
I'd like this to work like the methods that use CanBuildFrom and always keep the original type if possible. Is there a way? Or do Map subclasses always have to leave the value type as a type parameter?
Here's a complete compilable example:
import scala.collection.immutable
// pointless class that wraps another map and adds one method
class FixedMap(val impl : Map[String, Int])
extends immutable.Map[String, Int] with immutable.MapLike[String, Int, FixedMap] {
override val empty : FixedMap = FixedMap.empty
// This should return FixedMap if B1 is Int, and Map[String,B1]
// if B1 is a superclass of Int; but there's no way to do that.
// It is possible to return FixedMap here but then you have to
// throw at runtime if B1 is not Int
override def +[B1 >: Int](kv : (String, B1)) : Map[String, B1] = {
kv match {
case (k, v : Int) =>
new FixedMap(impl + Pair(k, v))
case _ =>
impl + kv
}
}
override def -(key : String) : FixedMap = {
new FixedMap(impl - key)
}
override def get(key : String) : Option[Int] = {
impl.get(key)
}
override def iterator : Iterator[(String, Int)] = {
impl.iterator
}
def somethingOnlyPossibleOnFixedMap() = {
println("FixedMap says hi")
}
}
object FixedMap {
val empty : FixedMap = new FixedMap(Map.empty)
}
object TestIt {
val empty = FixedMap.empty
empty.somethingOnlyPossibleOnFixedMap()
val one = empty + Pair("a", 1)
// Can't do the below because one is a Map[String,Int] not a FixedMap
// one.somethingOnlyPossibleOnFixedMap()
}
Here's what I'd try:
class FixedMap(val impl: immutable.Map[String, Int])
extends immutable.Map[String, Int] with immutable.MapLike[String, Int, FixedMap] {
override def +[B1 >: Int](kv: (String, B1)): immutable.Map[String, B1] = impl + kv
def +(kv: (String, Int))(implicit d: DummyImplicit): FixedMap = new FixedMap(impl + kv)
// ...
}
You're right: you cannot override the + that already exists, so you have to leave it there — otherwise your subclass wouldn't be able to do things that the superclasses can do, which violates the Liskov substitution principle. But you can add an additional method wich the exact arguments that you want (and you don't need a CanBuildFrom in this particular case).
The only problem is that the new method has the exact same type erasure as the one you were trying to override, but which has an incompatible signature. To solve this, you can add the DummyImplicit — defined in Predef as a class for which an implicit value is always available. Its main use is to work around type erasure in case of overloading like this.
Note that the static type of the map on which you want to call your overloaded method has to be FixedMap for this to work. If an object has a run-time type of FixedType but is statically typed to a regular Map[String, Int], the compiler won't call your new overloaded method.
It's possible to implement what you want using CanBuildFrom. The question is - do you really want/need to make it? The are several similar questions in SO, here is one of them (hope you will find answer there):
Extending Scala collections
Generally Scala gives use enough tools to avoid this (extending collections). And you really need a good reason to start with this.
It looks like it does work (best I can tell so far) if you add another + overload:
def +(kv : (String, Int))(implicit bf : CanBuildFrom[FixedMap, (String, Int), FixedMap]) : FixedMap = {
val b = bf(empty)
b ++= this
b += kv
b.result
}
The problem I was seeing doing this before was caused by returning FixedMap from the overridden +, thus preventing any upgrade to a generic map. I guess this allowed implicit conversion of the pair being +'d to work. But if you fix that overridden + method to return Map[String,B1] again, you can't use implicit conversion on the pair's value anymore. No way for the compiler to know whether to go to a superclass map i.e. Map[String,Any] or implicitly convert to Int in order to stick with FixedMap. Interesting that the return type of the method changes whether implicit conversions are used; I guess given a FixedMap return type the compiler can deduce that B1 is always just B (or something like that!).
Anyway this seems to be my bug; you just can't use implicit conversion on the pair._2 passed to + while being compatible with the Map interface, even conceptually. Now that I gave up on that, I think the overloaded + will work OK.

Mixing in generic traits in parameterized classes without duplicating type parameters

Let's assume I want to create a trait that I can mix in into any Traversable[T]. In the end, I want to be able to say things like:
val m = Map("name" -> "foo") with MoreFilterOperations
and have methods on MoreFilterOperations that are expressed in anything Traversable has to offer, such as:
def filterFirstTwo(f: (T) => Boolean) = filter(f) take 2
However, the problem is clearly that T is not defined as a type parameter on MoreFilterOperations. Once I do that, it's doable of course, but then my code would read:
val m = Map("name" -> "foo") with MoreFilterOperations[(String,String)]
or if I define a variable of this type:
var m2: Map[String,String] with MoreFilterOperations[(String,String)] = ...
which is way to verbose for my taste. I would like to have the trait defined in such a way that I could write the latter as:
var m2: Map[String,String] with MoreFilterOperations
I tried self types, abstract type members, but it hasn't resulted in anything useful. Any clues?
Map("name" -> "foo") is a function invocation and not a constructor, this means that you can't write:
Map("name" -> "foo") with MoreFilterOperations
any more that you can write
val m = Map("name" -> "foo")
val m2 = m with MoreFilterOperations
To get a mixin, you have to use a concrete type, a naive first attempt would be something like this:
def EnhMap[K,V](entries: (K,V)*) =
new collection.immutable.HashMap[K,V] with MoreFilterOptions[(K,V)] ++ entries
Using a factory method here to avoid having to duplicate the type params. However, this won't work, because the ++ method is just going to return a plain old HashMap, without the mixin!
The solution (as Sam suggested) is to use an implicit conversion to add the pimped method. This will allow you to transform the Map with all the usual techniques and still be able to use your extra methods on the resulting map. I'd normally do this with a class instead of a trait, as having constructor params available leads to a cleaner syntax:
class MoreFilterOperations[T](t: Traversable[T]) {
def filterFirstTwo(f: (T) => Boolean) = t filter f take 2
}
object MoreFilterOperations {
implicit def traversableToFilterOps[T](t:Traversable[T]) =
new MoreFilterOperations(t)
}
This allows you to then write
val m = Map("name"->"foo", "name2"->"foo2", "name3"->"foo3")
val m2 = m filterFirstTwo (_._1.startsWith("n"))
But it still doesn't play nicely with the collections framework. You started with a Map and ended up with a Traversable. That isn't how things are supposed to work. The trick here is to also abstract over the collection type using higher-kinded types
import collection.TraversableLike
class MoreFilterOperations[Repr <% TraversableLike[T,Repr], T] (xs: Repr) {
def filterFirstTwo(f: (T) => Boolean) = xs filter f take 2
}
Simple enough. You have to supply Repr, the type representing the collection, and T, the type of elements. I use TraversableLike instead of Traversable as it embeds its representation; without this, filterFirstTwo would return a Traversable regardless of the starting type.
Now the implicit conversions. This is where things get a bit trickier in the type notation. First, I'm using a higher-kinded type to capture the representation of the collection: CC[X] <: Traversable[X], this parameterises the CC type, which must be a subclass of Traversable (note the use of X as a placeholder here, CC[_] <: Traversable[_] does not mean the same thing).
There's also an implicit CC[T] <:< TraversableLike[T,CC[T]], which the compiler uses to statically guarantee that our collection CC[T] is genuinely a subclass of TraversableLike and so a valid argument for the MoreFilterOperations constructor:
object MoreFilterOperations {
implicit def traversableToFilterOps[CC[X] <: Traversable[X], T]
(xs: CC[T])(implicit witness: CC[T] <:< TraversableLike[T,CC[T]]) =
new MoreFilterOperations[CC[T], T](xs)
}
So far, so good. But there's still one problem... It won't work with maps, because they take two type parameters. The solution is to add another implicit to the MoreFilterOperations object, using the same principles as before:
implicit def mapToFilterOps[CC[KX,VX] <: Map[KX,VX], K, V]
(xs: CC[K,V])(implicit witness: CC[K,V] <:< TraversableLike[(K,V),CC[K,V]]) =
new MoreFilterOperations[CC[K,V],(K,V)](xs)
The real beauty comes in when you also want to work with types that aren't actually collections, but can be viewed as though they were. Remember the Repr <% TraversableLike in the MoreFilterOperations constructor? That's a view bound, and permits types that can be implicitly converted to TraversableLike as well as direct subclasses. Strings are a classic example of this:
implicit def stringToFilterOps
(xs: String)(implicit witness: String <%< TraversableLike[Char,String])
: MoreFilterOperations[String, Char] =
new MoreFilterOperations[String, Char](xs)
If you now run it on the REPL:
val m = Map("name"->"foo", "name2"->"foo2", "name3"->"foo3")
// m: scala.collection.immutable.Map[java.lang.String,java.lang.String] =
// Map((name,foo), (name2,foo2), (name3,foo3))
val m2 = m filterFirstTwo (_._1.startsWith("n"))
// m2: scala.collection.immutable.Map[java.lang.String,java.lang.String] =
// Map((name,foo), (name2,foo2))
"qaxfwcyebovjnbointofm" filterFirstTwo (_ < 'g')
//res5: String = af
Map goes in, Map comes out. String goes in, String comes out. etc...
I haven't tried it with a Stream yet, or a Set, or a Vector, but you can be confident that if you did, it would return the same type of collection that you started with.
It's not quite what you asked for, but you can solve this problem with implicits:
trait MoreFilterOperations[T] {
def filterFirstTwo(f: (T) => Boolean) = traversable.filter(f) take 2
def traversable:Traversable[T]
}
object FilterImplicits {
implicit def traversableToFilterOps[T](t:Traversable[T]) = new MoreFilterOperations[T] { val traversable = t }
}
object test {
import FilterImplicits._
val m = Map("name" -> "foo", "name2" -> "foo2", "name3" -> "foo3")
val r = m.filterFirstTwo(_._1.startsWith("n"))
}
scala> test.r
res2: Traversable[(java.lang.String, java.lang.String)] = Map((name,foo), (name2,foo2))
Scala standard library uses implicits for this purpose. E.g. "123".toInt. I think its the best way in this case.
Otherwise you'll have to go through full implementation of your "map with additional operations" since immutable collections require creation of new instances of your new mixed class.
With mutable collections you could do something like this:
object FooBar {
trait MoreFilterOperations[T] {
this: Traversable[T] =>
def filterFirstTwo(f: (T) => Boolean) = filter(f) take 2
}
object moreFilterOperations {
def ~:[K, V](m: Map[K, V]) = new collection.mutable.HashMap[K, V] with MoreFilterOperations[(K, V)] {
this ++= m
}
}
def main(args: Array[String]) {
val m = Map("a" -> 1, "b" -> 2, "c" -> 3) ~: moreFilterOperations
println(m.filterFirstTwo(_ => true))
}
}
I'd rather use implicits.