Thursday, December 22, 2011

Learning Scala : Reading the exotic and essential List API scaladoc 3

Authored by Win Myo Htet




def ++ [B] (that: GenTraversableOnce[B]): List[B]
[use case] Concatenates this list with the elements of a traversable collection.
def ::: (prefix: List[A]): List[A]
[use case] Adds the elements of a given list in front of this list.
Though they look cryptic, Scala is not as bad as certain language found in the Ocean. (Scala can be abused to be that bad, if you so desire.) The ++ function can concatenates with a other traversable collection while ::: only operates on two lists adding the parameter list in front. A code snippet is worth a thousand words
scala>  val list1=List(1,2,3,4,5)
list1: List[Int] = List(1, 2, 3, 4, 5)

scala> val list2=List(6,7,8,9,10)
list2: List[Int] = List(6, 7, 8, 9, 10)

scala> val array1=Array(11,12,13,14,15)
array1: Array[Int] = Array(11, 12, 13, 14, 15)

scala> list2.++(list1)
res8: List[Int] = List(6, 7, 8, 9, 10, 1, 2, 3, 4, 5)

scala> list2.++(array1)
res9: List[Int] = List(6, 7, 8, 9, 10, 11, 12, 13, 14, 15)

scala> list2++array1
res10: List[Int] = List(6, 7, 8, 9, 10, 11, 12, 13, 14, 15)

scala> list2.:::(list1)
res11: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> list1:::list2
res12: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> list1++list2
res13: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> list2.:::(array1)
<console>:10: error: type mismatch;
 found   : Array[Int]
 required: List[?]
              list2.:::(array1)
                        ^

We concatenate list2 and list1, and list2 and array1 using ++ function. As I have said the previous blog, Scala can omit dot and () for 0 or 1 parameter. Then, there is a standard call to :::. Since any function that ends with ":" binds to the right, the following ::: execution is literally, the same as the one above. We have introduced the ++ function operating on the list1 again to compare with ::: function operating on list2. They both give the same result. Prependening function ::: is always preferred over concatenating function ++ because ::: is constant execution. The last error using ::: function is a reminder that ++ has its place dealing with other traversal collection.

What if we want to prepand other traversal collection to our list, like the last error throwing expression, instead of concatenating function ++ which deals with other traversal collection?
def ++: [B] (that: TraversableOnce[B]): List[B]
[use case]Concatenates this list with the elements 
of a traversable collection. It differs from ++ in 
that the right operand determines the type of the 
resulting collection rather than the left one.
The use case description is a bit misleading with the word concatenating and comparing with ++. The justification for comparing with ++ function might be that ++: also deals with other traversal collection. It is also concatenating to the right oprand. I am just happy that the Scala library author does not overlook these usage.
scala> val array1=Array(1,2,3,4,5)
array1: Array[Int] = Array(1, 2, 3, 4, 5)

scala> val list2=List(6,7,8,9,10)
list2: List[Int] = List(6, 7, 8, 9, 10)

scala> list2.++:(array1)
res0: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> array1++:list2
res1: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)


There are also their overloaded function with lower bound and implicit parameter like product and sum we have seen in the previous blog.
def ++ [B >: A, That] (that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That
def ++ [B >: A, That] (that: TraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That
def ++: [B >: A, That] (that: Traversable[B])(implicit bf: CanBuildFrom[List[A], B, That]): That
def ++: [B >: A, That] (that: TraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That
def ::: [B >: A] (prefix: List[B]): List[B]
Here they are more permissible to deal with different types, thus the resulting collections are of List[Any].
scala> val listInt=List(1,2,3,4,5)
listInt: List[Int] = List(1, 2, 3, 4, 5)

scala> val listString=List("a","b","c","d")
listString: List[java.lang.String] = List(a, b, c, d)

scala> val arrayString=Array("e","f","g","h")
arrayString: Array[java.lang.String] = Array(e, f, g, h)

scala> listInt:::listString++arrayString
res0: List[Any] = List(1, 2, 3, 4, 5, a, b, c, d, e, f, g, h)

scala> arrayString++:listInt
res1: List[Any] = List(e, f, g, h, 1, 2, 3, 4, 5)

Since we have seen enough of the over loaded functions with lower bound and the implicit parameter, I won't be going over them separately for the rest of the functions.

The following functions deal with individual element prepanding/appending to the List.
def +: (elem: A): List[A]
def +: [B >: A, That] (elem: B)(implicit bf: CanBuildFrom[List[A], B, That]): That
def :+ (elem: A): List[A]
def :+ [B >: A, That] (elem: B)(implicit bf: CanBuildFrom[List[A], B, That]): That
def :: (x: A): List[A]
def :: [B >: A] (x: B): List[B]
:: and +: function prepand element to the list while :+ function append element to the list. List has two prepand function :: and +: since Scala has inherited :: function from the functional programming domain to begin with (Remember? we have seen :: as a sub class for case pattern matching in the first blog of this series.) and +: (and :+)is added later.
scala> val list=List(1,2,3,4,5)
list: List[Int] = List(1, 2, 3, 4, 5)

scala> 0+:list
res0: List[Int] = List(0, 1, 2, 3, 4, 5)

scala> -1::list
res1: List[Int] = List(-1, 1, 2, 3, 4, 5)

scala> list:+6
res2: List[Int] = List(1, 2, 3, 4, 5, 6)

scala> "a"+:list
res4: List[Any] = List(a, 1, 2, 3, 4, 5)

scala> list:+"z"
res5: List[Any] = List(1, 2, 3, 4, 5, z)

Again prepanding :: is preferred over appending. Wow, we are almost finished with the cryptic functions. I used to be intimidated browsing the List API seeing those function. Now that we have gone through it, it is clear that they are nothing to be intimidated about. It's easy ;) Let's get into a few left over cryptic functions.


Authored by Win Myo Htet

No comments:

Post a Comment