Search code examples
scalacharsequence

Scala Map of Strings not Compiling When CharSequence is expected


I'm trying to return a Map[CharSequence, CharSequence]. The point of the function is to check if another map has a certain key/value pair, and then return a particular CharSequence map.

If I just return an empty map (or string map), this compiles

def returnCharSequenceMap(someOtherMap: Option[Map[String,String]]): Map[CharSequence, CharSequence] = {
    Map.empty // or something like Map("A" -> "B")
}

However, this fails to compile

def returnCharSequenceMap(someOtherMap: Option[Map[String, String]]): Map[CharSequence, CharSequence] = {
    someOtherMap.map { mapRecord =>
        case Some("conditionA") =>
            Map("a" -> "b")
        case Some("conditionB") =>
            Map("a" -> "b", "c" -> "d")
        case _ => Map.empty
    }
}.getOrElse(Map.empty)

I get this rather obtuse error that I cannot decipher:

[error]  found   : scala.collection.immutable.Map[_19,String] where type _19 >: _1 <: CharSequence
[error]  required: Map[CharSequence,CharSequence]
[error] Note: _19 <: CharSequence, but trait Map is invariant in type A.
[error] You may wish to investigate a wildcard type such as `_ <: CharSequence`. (SLS 3.2.10)
[error]     }.getOrElse(Map.empty)

Can someone help point out what I'm doing wrong? I'm trying to understand why I can't just return the map. Thanks!


Solution

  • First, you cannot do pattern matching inside a function like this, without introducing it with the match keyword: what are you pattern matching on?

    Then, assuming you want to pattern match on mapRecord (in which case you can simply remove the mapRecord =>, since a function can be given as a pattern matching on its parameter) note that it will never match, since the function in map takes a parameter of type Map[String, String], not of type Option[Map[String, String]].

    While we're at it, you can use the collect method on Option (instead of map) to put only the interesting case in your patterns, and leave the case _ to be reduced as None, then to be dealt with in the getOrElse (thus avoiding to write Map.empty twice).

    Now to really answer your question, the problem is with type inference and the invariance property of Map on its first type parameter.

    To make sure that all the types are what you want them to be, you should put them as parameters to some of the functions that might need them. For instance, this code compiles:

    def returnCharSequenceMap(someOtherMap: Option[Map[String, String]]): Map[CharSequence, CharSequence] = {
      someOtherMap.map[Map[CharSequence, CharSequence]] { _ =>
        Map("a" -> "b")
      }.getOrElse(Map.empty)
    }