76545

Scala - covariant type in mutable collections

I am new in Scala world and now I am reading the book called "Scala in Action" (by Nilanjan Raychaudhuri), namely the part called "Mutable object need to be invariant" on page 97 and I don't understand the following part which is taken directly from the mentioned book.

<hr>

Assume ListBuffer is covariant and the following code snippet works without any compilation problem:

scala> val mxs: ListBuffer[String] = ListBuffer("pants") mxs: scala.collection.mutable.ListBuffer[String] = ListBuffer(pants) scala> val everything: ListBuffer[Any] = mxs scala> everything += 1 res4: everything.type = ListBuffer(1, pants)

Can you spot the problem? Because everything is of the type Any, you can store an integer value into a collection of strings. This is a disaster waiting to happen. To avoid these kinds of problems, it’s always a good idea to make mutable objects invariant.

<hr>

I would have the following questions..

1) What type of everything is in reality? String or Any? The declaration is "val everything: ListBuffer[Any]" and hence I would expect Any and because everything should be type of Any then I don't see any problems to have Integer and String in one ListBuffer[Any]. How can I store integer value into collection of strings how they write??? Why disaster??? Why should I use List (which is immutable) instead of ListBuffer (which is mutable)? I see no difference. I found a lot of answers that mutably collections should have type invariant and that immutable collections should have covariant type but why?

2) What does the last part "res4: everything.type = ListBuffer(1, pants)" mean? What does "everything.type" mean? I guess that everything does not have any method/function or variable called type.. Why is there no ListBuffer[Any] or ListBuffer[String]?

Thanks a lot,

Andrew

Answer1:

<strong>1</strong> This doesn't look like a single question, so I have to subdivide it further:

<ol> <li>"In reality" everything is ListBuffer[_], with erased parameter type. Depending on the JVM, it holds either 32 or 64 bit references to some objects. The types ListBuffer[String] and ListBuffer[Any] is what the compiler knows about it at compile time. If it "knows" two contradictory things, then it's obviously very bad.</li> <li>

"I don't see any problems to have Integer and String in one ListBuffer[Any]". There is no problem to have Int and String in ListBuffer[Any], because ListBuffer is invariant. However, in your hypothetical example, ListBuffer is covariant, so you are storing an Int in a ListBuffer[String]. If someone later gets an Int from a ListBuffer[String], and tries to interpret it as String, then it's obviously very bad.

</li> <li>

"How can I store integer value into collection of strings how they write?" Why would you want to do something that is obviously very bad, as explained above?

</li> <li>

"Why disaster???" It wouldn't be a major disaster. Java has been living with covariant arrays forever. It's does not lead to cataclysms, it's just bad and annoying.

</li> <li>

"Why should I use List (which is immutable) instead of ListBuffer (which is mutable)?" There is no absolute imperative that tells you to always use List and to never use ListBuffer. Use both when it is appropriate. In 99.999% of cases, List is of course more appropriate, because you use Lists to represent data way more often than you design complicated algorithms that require local mutable state of a ListBuffer.

</li> <li>

"I found a lot of answers that mutably collections should have type invariant and that immutable collections should have covariant type but why?". This is wrong, you are over-simplifying. For example, intensional immutable sets should be neither covariant, nor invariant, but contravariant. You should use covariance, contravariance, and invariance when it's appropriate. This little silly illustration has proven unreasonably effective for explaining the difference, maybe you too find it useful.

</li> </ol>

<strong>2</strong> This is a singleton type, just like in the following example:

scala> val x = "hello" x: String = hello scala> val y: x.type = x y: x.type = hello

Here is a longer discussion about the motivation for this.

Answer2:

I agree with most of what @Andrey is saying I would just add that covariance and contravariance belong exclusively to immutable structures, the exercisce that the books proposes is just a example so people can understand but it is not possible to implement a mutable structure that is covariant, you won't be able to make it compile. As an exercise you could try to implement a MutableList[+A], you'll find out that there is not way to do this without tricking the compiler putting asInstanceOf everywhere

Recommend

  • How to give photo to dialog from user's blob id?
  • Microsoft Collections for .NET [closed]
  • Array value not updated after changing variable value
  • OpenCL bytecode running on another card
  • Anonymous functions and Maps in Scala
  • Insert Path of a file with \\\\ in mysql using java
  • Using self.id to populate other fields in Django
  • Submission of new app with iAds
  • VB.Net Double comparison after some additions
  • What is the likely cause of a net::ERR_CONNECTION_ABORTED when uploading a file to Spring
  • Upper limits for fibonnacci
  • Smack 4.1.0 android Roster not displaying
  • Need code translation from VB to C#
  • What Makes These Two Array Adds Different?
  • WPF version of .ScaleControl?
  • How to make R's read_csv2() recognise the text characters properly
  • NUnit 3.0 TestCase const custom object arguments
  • Jenkins: FATAL: Could not initialize class hudson.util.ProcessTree$UnixReflection
  • Z3: Convert between FP and BitVector?
  • Sequential (transactional) API calls in angular 4 with state management
  • Eloquent paginate function in Slim 3 project using twig
  • Date Conversion from yyyy-mm-dd to dd-mm-yyyy
  • Email format validation in mvc3 view
  • CSS Linear-gradient formatting issue accross different browsers
  • C# - Is there a limit to the size of an httpWebRequest stream?
  • Counter field in MS Access, how to generate?
  • How to add date and time under each post in guestbook in google app engine
  • Javascript Callbacks with Object constructor
  • Convert array of 8 bytes to signed long in C++
  • Matrix multiplication with MKL
  • -fvisibility=hidden not passed by compiler for Debug builds
  • coudnt use logback because of log4j
  • How to CLICK on IE download dialog box i.e.(Open, Save, Save As…)
  • Turn off referential integrity in Derby? is it possible?
  • Bitwise OR returns boolean when one of operands is nil
  • Add sale price programmatically to product variations
  • MATLAB: Piecewise function in curve fitting toolbox using fittype
  • How to Embed XSL into XML
  • Unable to use reactive element in my shiny app
  • How do I use LINQ to get all the Items that have a particular SubItem?