SilentICE
SilentICE

Reputation: 700

How to combine Maps with different value types in Scala

I have the following code which is working:

case class Step() {
  def bindings(): Map[String, Any] = ???
}

class Builder {
  private val globalBindings = scala.collection.mutable.HashMap.empty[String, Any]
  private val steps = scala.collection.mutable.ArrayBuffer.empty[Step]

  private def context: Map[String, Any] =
    globalBindings.foldLeft(Map[String, Any]())((l, r) => l + r) ++ Map[String, Any]("steps" -> steps.foldLeft(Vector[Map[String, Any]]())((l, r) => l.+:(r.bindings)))
}

But I think it could be simplified so as to not need the first foldLeft in the 'context' method.

The desired result is to produce a map where the entry values are either a String, an object upon which toString will be invoked later, or a function which returns a String.

Is this the best I can do with Scala's type system or can I make the code clearer?

TIA

Upvotes: 0

Views: 601

Answers (1)

Ben Reich
Ben Reich

Reputation: 16324

First of all, the toMap method on mutable.HashMap returns an immutable.Map. You can also use map instead of the inner foldLeft together with toVector if you really need a vector, which might be unnecessary. Finally, you can just use + to add the desired key-value pair of "steps" to the map.

So your whole method body could be:

globalBindings.toMap + ("steps" -> steps.map(_.bindings).toVector)

I'd also note that you should be apprehensive of using types like Map[String, Any] in Scala. So much of the power of Scala comes from its type system and it can be used to great effect in many such situations, and so these types are often considered unidiomatic. Of course, there are situations where this approach makes the most sense, and without more context it would be hard to determine if that were true here.

Upvotes: 2

Related Questions