logo

Scala - Operators

Left Associative vs Right Associative

  • Left: a op b = a.op(b)
  • Right: a op b = b.op(a)

All:-ending operators are right associative

Operators

->: Create Tuple2

scala> val a = 1 -> 2
a: (Int, Int) = (1,2)

scala> val b = Tuple2(1,2)
b: (Int, Int) = (1,2)

scala> a == b
res30: Boolean = true

Create key-value pairs for Map

scala> Map(1 -> 2, 3 -> 4)
res32: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2, 3 -> 4)

_*

arbitrary long sequences; vararg expansion

<:: upper type bound

T <: A declares that type variable T refers to a subtype of type A

<%: view bound

>:: lower bound

The term T >: A expresses that the type parameter T or the abstract type T refer to a supertype of type A.

+T

declares type T to be used only in covariant positions.

-T

declare T to be used only in contravariant positions.

+: prepend(elem+:list) right-associative

scala> 1 +: List(1,2)
res21: List[Int] = List(1, 1, 2)

scala> (1 to 5).foldLeft(List[Int]())((a, b) => (b+:a))
res57: List[Int] = List(5, 4, 3, 2, 1)

scala> (1 to 5).foldLeft(List[Int]())((a, b) => b :: a).reverse
res45: List[Int] = List(1, 2, 3, 4, 5)

scala> (1 to 5) filter {_%2 == 0}
res46: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4)

:+ append(list:+elem)

scala> List(1,2) :+ 3
res23: List[Int] = List(1, 2, 3)

scala> (1 to 5).foldLeft(List[Int]())((a, b) => (a:+b))
res54: List[Int] = List(1, 2, 3, 4, 5)

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

:: prepend an element to a list(elem::list) right-associative

scala> 1 :: List(2,3)
res18: List[Int] = List(1, 2, 3)

scala> List(2,3).::(1)
res19: List[Int] = List(1, 2, 3)
scala> (1 to 5).foldLeft(List[Int]())((a, b) => b :: a)
res25: List[Int] = List(5, 4, 3, 2, 1)

::, +::: corollary operations

::: vs ++: concatenate 2 Lists

scala> (1 to 5).toList ::: (6 to 10).toList
res67: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
scala> val x = List(1, 2)
x: List[Int] = List(1, 2)

scala> val y = List(3, 4)
y: List[Int] = List(3, 4)

The two operators are equivalent if used as operators

scala> x ++ y
res9: List[Int] = List(1, 2, 3, 4)

scala> x ::: y
res10: List[Int] = List(1, 2, 3, 4)

However if used as method calls, they are different

scala> x.++(y)
res8: List[Int] = List(1, 2, 3, 4)

scala> x.:::(y)
res11: List[Int] = List(3, 4, 1, 2)

++ vs ++:

  • ++: left operand determines the type of the resulting collection
  • ++:: right operand determines the type of the resulting collection
scala> val x = List(1, 2)
x: List[Int] = List(1, 2)

scala> val y = scala.collection.mutable.LinkedList(3,4)
y: scala.collection.mutable.LinkedList[Int] = LinkedList(3, 4)

scala> x ++ y
res15: List[Int] = List(1, 2, 3, 4)

scala> x ++: y
res16: scala.collection.mutable.LinkedList[Int] = LinkedList(1, 2, 3, 4)

More Examples

scala> val a = Array(1,2,3)
a: Array[Int] = Array(1, 2, 3)

scala> val b = Array(4,5,6)
b: Array[Int] = Array(4, 5, 6)

scala> a ++ b
res1: Array[Int] = Array(1, 2, 3, 4, 5, 6)

scala> a :+ b
res2: Array[Any] = Array(1, 2, 3, Array(4, 5, 6))

scala> a +: b
res3: Array[Any] = Array(Array(1, 2, 3), 4, 5, 6)

:: prepend an element to a list(elem::list)

scala> (1 to 5).foldLeft(List[Int]())((a, b) => b :: a)
res25: List[Int] = List(5, 4, 3, 2, 1)

:+ append(list:+elem)

scala> (1 to 5).foldLeft(List[Int]())((a, b) => (a:+b))
res54: List[Int] = List(1, 2, 3, 4, 5)

+: prepend(elem+:list)

scala> (1 to 5).foldLeft(List[Int]())((a, b) => (b+:a))
res57: List[Int] = List(5, 4, 3, 2, 1)

scala> (1 to 5).foldLeft(List[Int]())((a, b) => b :: a).reverse
res45: List[Int] = List(1, 2, 3, 4, 5)

scala> (1 to 5) filter {_%2 == 0}
res46: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4)

::: concatenate 2 Lists

scala> (1 to 5).toList ::: (6 to 10).toList
res67: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)