The strange symbols in Scala

You will encounter various new symbols in Scala which are used in different constructs in scala. This blog will discuss such symbols and will also explain the different contexts they are used in.

Rocket (=>)

scala> (x:Int, y:Int)=>{x+y}
res12: (Int, Int) => Int = <function2>
  • It is used when a variable is passed-by-name. General syntax is varname :=>Type. For example
scala> def logIfTrue(shouldLog:Boolean, message: =>String) = {
 | if(shouldLog == true) println (message)
 | }
logIfTrue: (shouldLog: Boolean, message: => String)Unit
  • It is used in type declarations i.e. letters on rocket symbol. Fo e.g. A => R, (A,B) => R Another way to represent the same is Function[A[,B,…],R] They both mean that the function takes parameters of type A[,B…], and returns a value of type R.
  • () => R means that function has no input arguments (also called thunk)
  •  => () means that return type is Unit (basically no return type)
  • In ‘match’, they are used with  case For example case x => y.

Underscore ( _ )

  • An Underscore _ is used as a placeholder for parameters. For example, list.map(x=>x+2) can be written as list.map(_+2).
scala> l.map(x=>x+2)
res0: List[Int] = List(3, 4, 5)

scala> l.map(_+2)
res1: List[Int] = List(3, 4, 5)

When scala compiler sees an underscore as a placeholder, it looks for an a complete expression and replaces the underscore with the variable it expects to receive to evaluate the expression. In above example, _+2 is a complete expression, thus compiler expects that it will get one variable (because there is one underscore) and need to replace the underscore with that variable. Thus _+2 is equivalent to x=>x+2. Following are some other examples

list.map(_) corresponds to x=>list.map(x) because list.map is a  complete expression

_ + (2 * _) is equivalent to x => x + (y => 2 * y) because (2*y) is one expression and thus changes to y=>2*y. The resulting new expression is _ + (y=>2*y) which changes to x=>x+(y=>2*y)

_ + 2 * _ is same as (x, y) => x + 2 * y because _ + 2 * _ is one expression and as there are two underscores in this single expression, compiler expects two variables.

println _ is same as x=>println(x)

//simple function to print a list

scala> def printList(l:List[Int]) {
| l foreach (println _) //we could have written it as l foreach(x=>println(x))
| }
printList: (l: List[Int])Unit

scala> printList(l)
1
2
3

scala> printList(l.map(x=>x+1)) //could write this as l.map(_+1)
2
3
4

scala> printList(l.map(_+1))
2
3
4
  • An Underscore followed by colon and datatype indicates that you want to define a partially applied function. The argument for which the underscore is used is the argument which is not supplied
scala> def add(x:Int, y:Int) = {x+y}
add: (x: Int, y: Int)Int

//create a partially applied function incr. It still needs one argument 
//(denoted by _:Int) to become fully applied and be able to execute
scala> def incr = add(_:Int,1)
incr: Int => Int

scala> incr(2)
res2: Int = 3
  • An underscore is used for pattern matching in ‘match’ statement. It matches anything.
  • An underscore is used in import statement
  • An underscore is used as a placeholder for arguments in partial function and function literals.

Type ( [+A][-A][+S,-T]  )

These symbols denote covariant and contravariant subtype relationship in type parameter. This is covered in Type classes and Bounds

 Bounds  (A >: B, A <: B, A <% B, A : B =:=, <:<, <%<  )

These symbols denote Lower Bound (A>:B) , Upper Bound (A <:B), View Bounds ( A <% B) and Context bounds (A:B). This is covered in Type classes and Bounds

The other symbols are generally used in format Type1 =:= Type2 or Type1 <:< Type 2 or Type1 <%<Type2. This tells the compiler to ensure that Type1 is a same as Type 2 or Typ1 must be a subtype of Type2 or Type 1 must be viewable as Type2. If these constraints are not satisfied, the compiler will report an error. This is covered in Type classes and bounds

Generator <-

Used in for loops to generate values from the collections used in for loop construct.

Arrow ->

This is used to create tuples

//create Tuple2

scala> val nameTuple=("John","Edwards")
nameTuple: (String, String) = (John,Edwards)

//another way to create Tuple2

scala> "John" -> "Edwards"
res8: (String, String) = (John,Edwards)

// -> always creates Tuple 2. In this example, 1st element of tuple is a tuple

scala> "John" -> "Edwards" ->"Christian"
res9: ((String, String), String) = ((John,Edwards),Christian)

Annotations @

The symbol is used to specify instructions (a note ) for Scala compiler. An example of its use is discussed in recursion

TODO ???

??? (lets call it Todo) comes after a function definition like follows:

def testTBD (x:Int):String= ???

This functionality lets you add stub code (code which you yet have to implement or To be Done or To Do). You might have identified the functions you need in the code but may not necessarily need to implement all the functions immediately. Using ??? would be a good way to create the skeleton of your program.

If you call a function, which is not yet implemented, you’ll get NotImplementedError

class Test {
  def testTBD (x:Int):String= ???
  def printTest = println("test")
}

val t = new Test
t.printTest
test
t.testTBD(1) 
scala.NotImplementedError: an implementation is missing

 

 

Leave a comment