Implement a scala collection so that map, filter, etc. produce the right type?

Mutable maps are Builder s in Scala, so the MapFactory by default takes an empty map of the type in question to obtain a builder.

Mutable maps are Builders in Scala, so the MapFactory by default takes an empty map of the type in question to obtain a builder. If you have custom map build rules, one of the things you can do is to define your custom factory similar to collection.generic.MapFactory. You would have to define it in a similar way like there, but make both the empty method and the newBuilder method take an additional argument for the defaultValue.

Something along the lines of (if you read more about the Scala 2.8 collections API in the other link suggested, you'll find that you don't have to implement generic companion objects for maps): import collection. _ class DefaultingMapK, V(val defaultValue: V) extends mutable. HashMapK, V with mutable.

MapLikeK, V, DefaultingMapK, V { override def empty = new DefaultingMap(defaultValue) } object DefaultingMap { def newBuilderK, V(d: V): DefaultingMapK, V = new DefaultingMapK, V(d) implicit def canBuildFromK, V = new generic. CanBuildFromDefaultingMapK, V, (K, V), DefaultingMapK, V { def apply(from: DefaultingMapK, V) = newBuilderK, V(from. DefaultValue) def apply() = error("unsupported default apply") } } object Main { def main(args: ArrayString) { println((new DefaultingMapInt, Int(5)).

DefaultValue) println(((new DefaultingMapInt, Int(5)). Map(x => x)). DefaultValue) } } Prints: $ scalac defaulting.

Scala $ scala Main 5 5 I admit, still, this does not solve the problem for the parameterless apply.

The point about MutableMaps already being Builders is nice - that simplifies code in a few places. As to the parameterless apply, do you know when that gets invoked? Perhaps if it's uncommon I'm not too worried about it.

– Steve Nov 19 '10 at 14:02 BTW, I think it might be clearer if you dropped the newBuilder method and just created the DefaultingMap directly. – Steve Nov 19 '10 at 14:23 Parameterless apply gets invoked in breakOut, which is the only place, to my knowledge... See the collection package object. And you're right about newBuilder.

However, I'd still leave the newBuilder method definition in the companion. If the Map s had companions that worked in the same way as Seq s, it would then become useful. Plus, it would make them compliant with standard MapFactory companions which have the newBuilder.

– axel22 Nov 19 '10 at 14:48 I don't mind having a broken breakOut if everything else works. =) – Steve Nov 19 '10 at 15:03.

If you use collection.immutable. Map in 2.8 or above, then the withDefault method is available to you: val m = collection.immutable. Map(1->"a", 2->"b", 3->"c") val n = m withDefaultValue "default" // n(7) will return "default" UPDATE If you're mapping over the collection, move the withDefaultValue to the end of the processing chain: val o = (for ((k, v).

The withDefaultValue method doesn't work with map either. Try val o = for ((k, v) Try doing the initial count like this: "ababcbbb". GroupBy(identity) mapValues { _.

Size } – Kevin Wright Nov 19 '10 at 11:50 Putting the withDefaultValue at the end of the processing chain isn't really a good option. I may not know where the end of the processing chain is, particularly if I return this object to someone else. I won't know what their processing chain looks like.

– Steve Nov 19 '10 at 11:59 How do you propose to have the default value persist through mappings? For example: n map {_. ToString} - The only way this would work is if every map held a reference to all maps it came from, and the mapping was performed lazily.

Think of the poor garbage collector... – Kevin Wright Nov 19 '10 at 12:16 Why does it need to hold a reference to all maps it came from? Why can't it just hold a reference to the default value (or default value function). And for the case of n.

Map(_. ToString), that shouldn't even produce a Map, it should produce an Iterable, so it's perfectly fine if the default is lost there. Basically you should only lose the default when you have to.

This is much the same philosophy as BitSet - when you bitset. Map(_. ToString), you get a Set back instead of a BitSet.

– Steve Nov 19 '10 at 12:41.

The Scala 2.8 Collections API is a very nice document and I seem to remember it discussing this aspect of transformation, though I don't remember exactly where. I guess that isn't very helpful...

2 No, not so much. ;-) – Steve Nov 19 '10 at 11:29.

Ok, here's an approach that's very, very close to what I want: class DefaultingMapK, V(defaultValue: => V) extends mutable. HashMapK, V with mutable. MapLikeK, V, DefaultingMapK, V { override def empty = new DefaultingMapK, V(defaultValue) override def default(key: K): V = { val result = this.

DefaultValue this(key) = result result } implicit def canBuildFromNK = new generic. CanBuildFromDefaultingMapK, V, (NK, V), DefaultingMapNK, V { def apply(from: DefaultingMapK, V) = new DefaultingMapNK, V(from. NewDefaultValue) def apply() = new DefaultingMapNK, V(defaultValue) } def newDefaultValue = defaultValue } Now, if I get that CanBuildFrom into scope, everything works like a charm: scala> val counter = new DefaultingMapChar, Int(0) counter: DefaultingMapChar,Int = Map() scala> for (c import counter.

_ import counter. _ scala> counter. Map{case (k, v) => (k, v * 2)} res1: DefaultingMapChar,Int = Map((a,4), (c,2), (b,10)) scala> for ((k, v) 1) yield (k.

ToString, v * 2) res2: DefaultingMapjava.lang. String,Int = Map((a,4), (b,10)) However, if I leave off that import counter. _, I get the same behavior as before.

If I can just figure out how to get that implicit def canBuildFrom to be found, I'll be set...

Note that this degrades when doing counter. Map{case (k, v) => (k, v. ToString)}.

Now the default value is of type Any. – Debilski Nov 19 '10 at 12:11 That's the correctly inferred type - you have String elements but an Int default and the only thing they share in common is Any. But I think you're probably right that it would be more useful to just drop the NV >: V in favor of V alone so that you get a HashMapChar, String back instead in this case.

– Steve Nov 19 '10 at 12:26 Ok, I edited it as suggested - it's no longer canBuildFromNK, NV >: V but just simply canBuildFromNK. – Steve Nov 19 '10 at 12:28.

It won’t help you with the return type of map (but then again, the default value of the new collection cannot generally be defined by using the map transformation). But to give you another approach: class DefaultHashMapA, B(dflt: => B) extends scala.collection.mutable. MapA, B { val underlying = new scala.collection.mutable.

HashMapA, B() def get(key: A) = underlying. Get(key) orElse Some(default(key)) def iterator: Iterator(A, B) = underlying. Iterator def +=(kv: (A, B)) = { underlying += kv; this } def -=(key: A) = { underlying -= key; this } override def empty: DefaultHashMapA, B = new DefaultHashMapA, B(dflt) override def default(key: A) = dflt }.

1 Yeah, unfortunately, the return type of map is pretty much the crux of the problem. I need those default values to stick around. – Steve Nov 19 '10 at 12:30.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions