Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't mutable.Map extend immutable.Map?

Tags:

scala

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.

like image 341
nornagon Avatar asked Mar 14 '18 15:03

nornagon


People also ask

How can we convert mutable Map to immutable in Java?

You can simply create a new HashMap from the existing Map using the copy constructor. HashMap<String, Object> = new HashMap<>(immutableMap);

Are Maps immutable in Scala?

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.

How can we convert mutable to immutable Scala?

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.

Is Map mutable in Java?

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.


2 Answers

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)

like image 61
Andrey Tyukin Avatar answered Sep 28 '22 14:09

Andrey Tyukin


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.)

like image 23
Mike Allen Avatar answered Sep 28 '22 15:09

Mike Allen