This code works:
@ mutable.Seq(1, 2).asInstanceOf[Seq[Int]]
res1: Seq[Int] = ArrayBuffer(1, 2)
But this doesn't:
@ mutable.Map(1 -> 2).asInstanceOf[Map[Int, Int]]
java.lang.ClassCastException: scala.collection.mutable.HashMap cannot be cast
to scala.collection.immutable.Map
  ammonite.$sess.cmd1$.<init>(cmd1.sc:1)
  ammonite.$sess.cmd1$.<clinit>(cmd1.sc)
Why can mutable.Seq be viewed as immutable, but not mutable.Map? I understand that casting a mutable Seq to an immutable one is "lying" about the mutability of the underlying collection, but in some situations the programmer knows better—e.g. when returning a collection from a function which uses a mutable list to build up a result, but returns an immutable value.
You can simply create a new HashMap from the existing Map using the copy constructor. HashMap<String, Object> = new HashMap<>(immutableMap);
Thanks to that, we have direct access to a value under a given key. Scala defines two kinds of maps, the immutable, which is used by default and mutable, which needs an import scala. collection.
Generally, from mutable to immutable, you use the to* series methods in mutable collections, like MutableList and ListBuffer's toList method. In the other hand, from immutable to mutable, you can just use constructors like this: scala. collection. mutable.
Mutable maps supports modification operations such as add, remove, and clear on it. Unmodifiable Maps are “read-only” wrappers over other maps. They do not support add, remove, and clear operations, but we can modify their underlying map.
The default Map is defined in Predef as 
type Map[A, +B] = collection.immutable.Map[A, B]
so it is explicitly immutable, and mutable.Map is not a subclass of it.
In contrast to that, the default Seq is defined directly in scala as 
type Seq[+A] = scala.collection.Seq[A] 
so it is a supertype of both mutable.Seq and immutable.Seq. This is why your first asInstanceOf does not fail: every mutable.Seq is also a collection.Seq.
As explained here, the decision to not specify whether Seq has to be mutable or immutable had something to do with support for arrays and varargs.
In 2.13, the default Seq will become immutable, and a new type ImmutableArray will be introduced to deal with varargs. (Thanks @SethTisue for pointing it out)
The primary problem is this:
If scala.collection.mutable.Map was a subclass of scala.collection.immutable.Map, then the former is-a latter too. That is, a mutable Map is also immutable. Does that make sense?
To illustrate this, you could pass an instance of a mutable Map to a function or constructor expecting an immutable Map. Alas, the two types have different semantics: if you, say, add an element to the immutable version, you'll get a new immutable Map instance returned; yet if you add an element to the mutable version, it changes that instance's contents—thus, it will have a side-effect.
As a consequence, if you wanted to write a pure, referentially transparent (RT) function (i.e. one that has no side-effects) that takes an immutable Map argument, you couldn't achieve your goal—anyone could screw that up by passing it a mutable Map instance instead. This would then change the meaning of your code and potentially cause all manner of problems.
In functional programming, immutability is big deal, as is RT. By ensuring that the two cannot be confused, programs that need immutable Maps can guarantee that they will get them.
(Of course, if you explicitly want to write code that will accept either, you could request an instance of their common scala.collection.Map trait instead.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With