Scala Foundation Course - Placeholder Syantax


We learned about functions and function literals. There are few more concepts associated with the functions and function literals. In this video, I will talk about following items.

  1. Placeholder syntax
  2. Function values
  3. Local Functions

Scala Placeholder syntax

Let's start with the placeholder syntax. We have seen the below example earlier.

                                
    val r = 1 to 10
    r.map(x => x + 10)                                      
                         

Let me show you another one.

                                
    r.reduce((x,y) => x + y )                                           
                         

The reduce method is another Higher Order function on Scala collections. Do you understand how the reduce works? The reduce method takes a binary operator function as input. Then it applies the function to the collection. That is why, in this example, we are passing a function literal that takes two input parameters. Like a map method, the reduce method is also a looping construct. In the first iteration, the first element goes as x and the second item replaces y. It collects the output. In this example, it would be x+y.
In the next iteration, the output from the previous iteration goes as x and the third element moves as y. This process repeats till the end, and we get the sum of the entire range as a result.
We used simple sum, but you can use different algorithms in this loop to get a different type of information from the collection. Here are some examples.

                                
    r.reduce((x,y) => x * y)
    r.reduce((x,y) => x max y)
    r.reduce((x,y) => x + y / x min y)                                      
                         

We are not using type annotation for x and y. I covered it in the earlier video, so you already know the reason. Right? We don't use a type annotation because Scala already knows the type. But why the hell are we using the parameter list? I mean, Scala already knows that the reduce method takes a function with two arguments. Why can't we remove the argument list from there? Why do I still need to code it? That's where the placeholder syntax is useful. Let's me explain.

                                
    r.map(x => x + 10)
    r.reduce((x,y) => x * y)                                       
                         

Look at the above method calls. What are we passing there? We are giving a function literal. It contains two parts. A list of parameters and the body. In the first case (the map method), Scala knows that you will pass a function that takes a single parameter. That restriction is imposed by the definition of the map method.
In the second case (the reduce method), Scala knows that you will pass a function that takes two input parameters. Again, that restriction is imposed by the definition of the reduce method. Right?
So, the list of arguments becomes optional. We can leave it because Scala already knows it. Let us remove that part.

                                
    r.map(x + 10)
    r.reduce(x * y)                                        
                         

Now, the Scala compiler will complain. What is x? and What is y? is it a free variable? No, Right? Those are parameters. So, we need to replace the reference to x with an underscore and write it like below.

                                
    r.map(_ + 10)
    r.reduce(_ * _ )                                        
                         

The above syntax is known as the placeholder syntax.The placeholder syntax makes it possible to remove the list of function arguments. We only give the body and tell Scala that we want to use the parameter at the place of the underscore. That's it. Scala already knows everything else.
Similarly, in secondexample, we have two arguments, and we know that we need the first argumentbefore the *, and the second parameter after the *. So, Scala allows you to write it like this.

                                
    r.reduce( _ * _ )                                             
                         

These underscores are a fill in the blanks for Scala. The compiler will fill in first parameter to the first place and the second parameter to the second place. The only point to remember is this.
The first underscore represents the first parameter. The second underscore represents the second parameter. The third underscore represents the third parameter and so on. Hence, the number of parameters and the number of underscores must be same. Right? Scala will fill in parameters in a sequence.
Now, a simple quiz. Can you write below example using a placeholder syntax?

                                
    r.filter(x => x > 5)                                           
                         

Here is the answer.

                                
    r.filter(_ > 5)                                           
                         

Can you do this one also?

                                
    r.reduce((x,y) => x + y / x min y)                                           
                         

The answer is "No" There are two parameters, but we are using them more than once. In this case, we need four underscores, but that violates the rule that the number of parameters and the number of underscores must match.
Great! The placeholder syntax is frequently used for a single line and simple function literals. You will often see that in your Scala journey. Just remember that the placeholder syntax allows you to remove the first part of the function literal and replace the parameter instances with an underscore.

Scala Function value

There is another confusing term. The function values. A beginner is often confused with a function literal and a function value. We already learned about function literals. The following code represents a function literal. Right?

                                
    val f = (x:Int) => x + 10                                          
                         

Do you know what happens internally? When you compile the above code, Scala will generate a class for that literal. The compiler will instantiate the class as an object and assign it to the value f. The generated code looks like below.

                                
    val f1 = new Function1[Int, Int] {
        def apply(x: Int): Int = x + 10
    }                                       
                         

Typically, we use the function literal in two possible ways.

  1. Assign it to a value as we do in the above example.
  2. Pass it to a higher-order function or return it from a higher-order function.

In both cases, Scala compiler will generate a class for the function literal, instantiate the class as an object and assign it to a value. So, the function value is an object whereas a function literal is a source code for it. The literal is like a class, and the value is an object.
In the above example, f is a function value whereas the code there is a function literal. That's it.

Local Functions in Scala

The next one is the local function, and it should be the simplest idea among all others that we learned so far. When we use an Object-Oriented approach, it is quite common to create private methods. They are a kind of helper methods, and we make them private because we don't want them to expose to the external world. Scala offers the same notion using the local functions. You can define functions inside other functions. They are visible only in their enclosing block. Here is an example.

                                
    import scala.io.Source
    import scala.io.Source._
    def getErrors(fileName: String) = {
                                    
        def isError(line :String) = {
            if (line.contains("error")) true else false
        }   
                                    
        val f = Source.fromFile(fileName)
            for (l <- f.getLines() if isError(l)) yield l  
    }
    getErrors("/root/mylog.dat") foreach println                                        
                         

The getErrors function takes a file name as input, and it returns the error messages. We are using isError as a local function. Simple as that. Sometimes, people also refer them as Nested Function. The choice is yours, call them Nested or Local, but they are the same thing.
Thank you very much.


You will also like:


Scala Functions

Scala is a functional programming language. Functions are the building blocks in Scala.

Learning Journal

First Class Functions

Function is a first-class citizen in functional programming. What does it mean?

Learning Journal

Hadoop Security

Hadoop security implementation using Kerberos.

Learning Journal

Scala placeholder syntax

What is a scala placeholder syntax and why do we need it? Learn from experts.

Learning Journal

Spark in Google cloud

Learn How to Install Hadoop and Spark in Google Cloud in just 2 minuts.

Learning Journal