From 9bd74024a120aca0c777ee3917084776875daa69 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Tue, 19 Oct 2010 22:14:29 +0000 Subject: A modified approach to map withDefault[Value]. --- src/library/scala/collection/Map.scala | 24 +++++++----------------- src/library/scala/collection/immutable/Map.scala | 16 +++++++++++++++- src/library/scala/collection/mutable/Map.scala | 12 ++++++++---- test/files/run/t3829.scala | 8 ++------ 4 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/library/scala/collection/Map.scala b/src/library/scala/collection/Map.scala index 6841ad14d0..6196093219 100644 --- a/src/library/scala/collection/Map.scala +++ b/src/library/scala/collection/Map.scala @@ -6,8 +6,6 @@ ** |/ ** \* */ - - package scala.collection import generic._ @@ -30,12 +28,6 @@ import generic._ */ trait Map[A, +B] extends Iterable[(A, B)] with MapLike[A, B, Map[A, B]] { def empty: Map[A, B] = Map.empty - - /** The same map with a given default function */ - def withDefault[B1 >: B](d: A => B1): Map[A, B1] = new Map.WithDefault[A, B1](this, d) - - /** The same map with a given default value */ - def withDefaultValue[B1 >: B](d: B1): Map[A, B1] = new Map.WithDefault[A, B1](this, x => d) } /** $factoryInfo @@ -48,15 +40,13 @@ object Map extends MapFactory[Map] { /** $mapCanBuildFromInfo */ implicit def canBuildFrom[A, B]: CanBuildFrom[Coll, (A, B), Map[A, B]] = new MapCanBuildFrom[A, B] - class WithDefault[A, +B](underlying: Map[A, B], d: A => B) extends Map[A, B] { - override def size = underlying.size - def get(key: A) = underlying.get(key) orElse Some(default(key)) - def iterator = underlying.iterator - override def empty = new WithDefault(underlying.empty, d) - override def updated[B1 >: B](key: A, value: B1): WithDefault[A, B1] = new WithDefault[A, B1](underlying.updated[B1](key, value), d) - override def + [B1 >: B](kv: (A, B1)): WithDefault[A, B1] = updated(kv._1, kv._2) - def - (key: A): WithDefault[A, B] = new WithDefault(underlying - key, d) + /** An abstract shell used by { mutable, immutable }.Map but not by collection.Map + * because of variance issues. + */ + abstract class WithDefault[A, +B](underlying: Map[A, B], d: A => B) extends Map[A, B] { + override def size = underlying.size + def get(key: A) = underlying.get(key) orElse Some(default(key)) + def iterator = underlying.iterator override def default(key: A): B = d(key) } - } diff --git a/src/library/scala/collection/immutable/Map.scala b/src/library/scala/collection/immutable/Map.scala index ef1f6b60ed..272caec5ea 100644 --- a/src/library/scala/collection/immutable/Map.scala +++ b/src/library/scala/collection/immutable/Map.scala @@ -7,7 +7,6 @@ \* */ - package scala.collection package immutable @@ -32,6 +31,12 @@ trait Map[A, +B] extends Iterable[(A, B)] override def empty: Map[A, B] = Map.empty + /** The same map with a given default function */ + def withDefault[B1 >: B](d: A => B1): immutable.Map[A, B1] = new Map.WithDefault[A, B1](this, d) + + /** The same map with a given default value */ + def withDefaultValue[B1 >: B](d: B1): immutable.Map[A, B1] = new Map.WithDefault[A, B1](this, x => d) + /** Add a key/value pair to this map. * @param key the key * @param value the value @@ -52,6 +57,15 @@ object Map extends ImmutableMapFactory[Map] { def empty[A, B]: Map[A, B] = EmptyMap.asInstanceOf[Map[A, B]] + class WithDefault[A, +B](underlying: Map[A, B], d: A => B) extends collection.Map.WithDefault[A, B](underlying, d) with Map[A, B] { + override def empty = new WithDefault(underlying.empty, d) + override def updated[B1 >: B](key: A, value: B1): WithDefault[A, B1] = new WithDefault[A, B1](underlying.updated[B1](key, value), d) + override def + [B1 >: B](kv: (A, B1)): WithDefault[A, B1] = updated(kv._1, kv._2) + override def - (key: A): WithDefault[A, B] = new WithDefault(underlying - key, d) + override def withDefault[B1 >: B](d: A => B1): immutable.Map[A, B1] = new WithDefault[A, B1](underlying, d) + override def withDefaultValue[B1 >: B](d: B1): immutable.Map[A, B1] = new WithDefault[A, B1](underlying, x => d) + } + @serializable private object EmptyMap extends Map[Any, Nothing] { override def size: Int = 0 diff --git a/src/library/scala/collection/mutable/Map.scala b/src/library/scala/collection/mutable/Map.scala index 047db08142..5df8594a16 100644 --- a/src/library/scala/collection/mutable/Map.scala +++ b/src/library/scala/collection/mutable/Map.scala @@ -27,10 +27,10 @@ trait Map[A, B] override def empty: Map[A, B] = Map.empty /** The same map with a given default function */ - def withDefault(d: A => B): Map[A, B] = new Map.WithDefault[A, B](this, d) + def withDefault(d: A => B): mutable.Map[A, B] = new Map.WithDefault[A, B](this, d) /** The same map with a given default value */ - def withDefaultValue(d: B): Map[A, B] = new Map.WithDefault[A, B](this, x => d) + def withDefaultValue(d: B): mutable.Map[A, B] = new Map.WithDefault[A, B](this, x => d) /** Return a read-only projection of this map. !!! or just use an (immutable) MapProxy? def readOnly : scala.collection.Map[A, B] = new scala.collection.Map[A, B] { @@ -63,7 +63,11 @@ object Map extends MutableMapFactory[Map] { override def updated[B1 >: B](key: A, value: B1): WithDefault[A, B1] = new WithDefault[A, B1](underlying.updated[B1](key, value), d) override def + [B1 >: B](kv: (A, B1)): WithDefault[A, B1] = updated(kv._1, kv._2) override def - (key: A): WithDefault[A, B] = new WithDefault(underlying - key, d) - } + /** If these methods aren't overridden to thread through the underlying map, + * successive calls to withDefault* have no effect. + */ + override def withDefault(d: A => B): mutable.Map[A, B] = new WithDefault[A, B](underlying, d) + override def withDefaultValue(d: B): mutable.Map[A, B] = new WithDefault[A, B](underlying, x => d) + } } - diff --git a/test/files/run/t3829.scala b/test/files/run/t3829.scala index 49fbbe6363..a7d03f34eb 100644 --- a/test/files/run/t3829.scala +++ b/test/files/run/t3829.scala @@ -1,13 +1,9 @@ - - - - // ticket #3829 object Test { - import collection._ + import collection.{ mutable, immutable } def main(args: Array[String]) { - val map = Map(1 -> 2, 3 -> 4) + val map = immutable.Map(1 -> 2, 3 -> 4) assert(map.get(0) == None) val defmap = map.withDefaultValue(-1) -- cgit v1.2.3