Search code examples
scaladictionaryreturn-value

Scala - Map with default value None?


Given

trait A
case class B extends A

trait C

I'm trying to implement something akin to this:

val m = scala.collection.mutable.HashMap[String, C=>Option[A]](
    ... //some pre-defined mappings
).withDefaultValue((_:C) => None)

This will give me a type mismatch:

expected: C=>Option[A], actual: C=>None.type

I heard scala expects None to be returned from a catch clause, so I tried the very ugly

val m = scala.collection.mutable.HashMap[String, C=>Option[A]](
    ... //some pre-defined mappings
).withDefaultValue((_:C) => try {
    throw new RuntimeException()
    Some(B())
  } catch{ case _ => None}
)

But that (thankfully) didn't work either:

type mismatch, expected: C=>Option[A], actual: C=>Option[B]

What's the proper way to do what I am trying to?


Solution

  • None is an instance of Option[Nothing]. But Option is covariant in its type parameter, and Nothing is a subtype of everything.

    This means that None is a subtype of Option[A]. Just say so:

    None: Option[A]
    

    But type inference can usually do it for you. If you create the function in advance,

    val default = (c: C) => None
    

    then you'll get the wrong return type and need to specify it, but withDefaultValue should already know the type of your map.