Adding an item to an immutable Seq

Nikita Volkov picture Nikita Volkov · Nov 28, 2011 · Viewed 78.5k times · Source

Say, I have a sequence of strings as an input and I want to get a new immutable Seq which consists of elements of the input and an item "c". Here are two methods that I've discovered to be working:

  1. assert(Seq("a", "b", "c") == Seq("a", "b") ++ Seq("c")) - the problem with this one is that it seems that instantiating a temporary sequence (Seq("c")) just for the sake of the operation is rendundant and will result in overhead
  2. assert(Seq("a", "b", "c") == List("a", "b") ::: "c" :: Nil) - this one restricts the type of input collection to be a List, so Seq("a", "b") ::: "c" :: Nil won't work. Also it seems that instantiating a Nil may aswell result in overhead

My questions are:

  1. Is there any other way of performing this operation?
  2. Which one is better?
  3. Isn't Seq("a", "b") ::: Nil not being allowed a flaw of Scala's developers?

Answer

Ben James picture Ben James · Nov 28, 2011

Use the :+ (append) operator to create a new Seq using:

val seq = Seq("a", "b") :+ "c"
// seq is now ("a","b","c")

Note: :+ will create a new Seq object. If you have

val mySeq = Seq("a","b")

and you will call

mySeq :+ "c"

mySeq will still be ("a","b")

Note that some implementations of Seq are more suitable for appending than others. List is optimised for prepending. Vector has fast append and prepend operations.

::: is a method on List which requires another List as its parameter - what are the advantages that you see in it accepting other types of sequence? It would have to convert other types to a List. If you know that List is efficient for your use case then use ::: (if you must). If you want polymorphic behaviour then use the generic ++.

There's no instantiation overhead to using Nil; you don't instantiate it because it's a singleton.