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

I can’t figure out how to handle overriding the β€œ+” in an immutable map if the map can only store an invariant type for its values.

Sort of:

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 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 would like this to work as methods that use CanBuildFromand always preserve the original type, if possible. Is there any way? Or should Map subclasses always leave the value type as the type parameter?

Here is a complete compiled 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 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()
}
+3
source share
3 answers

Here is what I will 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)

  // ...

}

: +, , - , , . , ( CanBuildFrom ).

, , , , . , DummyImplicit - Predef , . - , .

, , , FixedMap . FixedType, Map[String, Int], .

+2

, , CanBuildFrom. - / ? SO, (, ):

Scala

Scala , ( ). , .

+1

, ( ), + :

def +(kv : (String, Int))(implicit bf : CanBuildFrom[FixedMap, (String, Int), FixedMap]) : FixedMap = {
    val b = bf(empty)
    b ++= this
    b += kv
    b.result
}

, , FixedMap +, . , , + . overridden +, Map [String, B1], . , , Map [String, Any] Int, FixedMap. , ; , FixedMap , B1 B ( - !).

Anyway, this seems to be my mistake; you simply cannot use the implicit conversion to pair._2 passed to +, being compatible with the map interface, even conceptually. Now that I have given up on this, I think that overloaded + will work fine.

-1
source

All Articles