Mike Slinn

Collection Extras

— Draft —

Published 2014-03-10. Last modified 2020-02-11.
Time to read: 2 minutes.

This lecture discusses more advanced aspects of working with collections and converters.

Scala 2.13 Collection Compatibility Library And Migration Tool

A compatibility library is available for Scala 2.11, 2.12 and 2.13. This library can do many things, most of which are only of interest to library authors. This course does not cover the advanced topics that library authors might be interested in, so we'll only discuss a portion of the library's capability: how to use the latest 2.13 collections API for projects that are stuck with an older version of Scala such as 2.11 or 2.12. At the time this lecture was last updated the library was a work in progress.

To use the library this way, add the following dependency to build.sbt:

build.sbt fragment
"org.scala-lang.modules" %% "scala-collection-compat" % "2.1.4"

Import the library into the current scope like this:

Scala code
import scala.collection.compat._

As you have already seen, Scala 2.13's conversions use parentheses. Scala 2.11 and 2.12 used square brackets after the to method instead of parentheses.

Scala REPL
scala> Array(1, 2, 3).to[List] // old syntax (square braces)
res9: List[Int] = List(1, 2, 3) 

With this compatibility library you can also use the 2.13 syntax, which uses parentheses after the to method, from older versions of Scala.

Scala code
import scala.collection.compat._
Array(1, 2, 3).to(List)   // Scala 2.13 syntax (parentheses)

The sample code contains an sbt project called compatLibDemo that demonstrates this.

Collection Conversions with Implicitly

As discussed in the  Implicit Conversions lecture earlier in this course, you can access the implicit method to discover potential implicit conversions between two types. The implicitly method can check if an implicit converter of a given type is available and returns it if so. This section builds on the previously presented material and discusses implicit conversions between collections.

For example, Option can be implicitly converted to Iterable, as you can see in the inheritance diagram for Option.

Scala uses implicit conversions extensively in order to make it seem as if types (such as Option) are subclasses of a trait (such as Iterable). If it quacks like a duck, and walks like a duck, it is a duck for all practical purposes and we don't need to investigate its lineage.

We can use the implicitly method in the REPL to discover the method that performs the implicit conversion from Option to Iterable.

Scala REPL
scala> val oiToIi = implicitly[Option[Int] => Iterable[Int]]
toiToIi: Some[Int] => scala.collection.Iterable[Int] = <function1>
scala>
oiToIi(Some(123)) res15: Iterable[Int] = Iterable(123)

We can also use the long form syntax to obtain the same implicit conversion method. Both of these syntaxes were discussed in the More Fun With Functions lecture of the Introduction to Scala course.

Scala REPL
scala> val oiToIi2 = implicitly[Function1[Option[Int], Iterable[Int]]]
oiToIi2: Option[Int] => Iterable[Int] = $$Lambda$1088/0x000000084062d040@502aa66a
scala>
oiToIi2(None) res18: Iterable[Int] = List()

It doesn't matter if we try to convert from Option[A] to Iterable[A], or from Some[A] to Iterable[A]. because Some is a subclass of Option.

Scala REPL
scala> implicitly[Some[Int] => Iterable[Int]]
res11: Some[Int] => Iterable[Int] = <function1> 

FYI, here is the source code for option2Iterable, which is the implicit conversion function that converts from Option to Iterable, as found in the source code for Option:

Scala code
object Option {
    /** An implicit conversion that converts an option to an iterable value */
  implicit def option2Iterable[A](xo: Option[A]): Iterable[A] =
    if (xo.isEmpty) Iterable.empty else Iterable.single(xo.get)

  /** An Option factory which creates Some(x) if the argument is not null, and None if it is null.
   *  @param  x the value
   *  @return Some(value) if value != null, None if value == null */
  def apply[A](x: A): Option[A] = if (x == null) None else Some(x)

  /** An Option factory which returns `None` in a manner consistent with the collections hierarchy. */
  def empty[A] : Option[A] = None

  // ...
}

* indicates a required field.

Please select the following to receive Mike Slinn’s newsletter:

You can unsubscribe at any time by clicking the link in the footer of emails.

Mike Slinn uses Mailchimp as his marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp’s privacy practices.