Basics of Scala functions

Let's start with the Typical syntax to define a function.

                                        
    def functionName ([<parameterName> : <type> [, ....]]) : [return type] = {
        function body
        return [expr]
        }              
                                    

The def starts a function definition.
Then you give a name or an identifier.
The next one is the parameter list. You can provide a list of parameters in a parenthesis.
Then comes the return type of the function and finally, the body.
One important thing to remember is that the function must return something. If you think that it does not need to return a meaningful value, it should return a Unit value. But it must return a value.


Optional elements of Scala Functions

The first source of confusion is the optional part of this syntax.
Let's create an example function.

                                        
    def myMax(x:Int, y:Int) : Int = {
        if (x > y) 
            return x;
        else 
            return y;
        }                 
                                    

We will use this example to understand the optional components of a Scala Function.
So, first thing first.

Semicolon

The semicolon is optional. You might be wondering that if there is no semicolon then how do we terminate the expression? The answer to this question is another question.
Why do you want to use two line terminators?
You are already pressing an enter key at the end of every line.
Why do you want to enter a semicolon as well?
Scala recommends you to type one expression per line. As a programmer, we already do it to keep our code well formatted and readable. However, if you want to be sloppy and write more than one expressions on a single line, use a semicolon.
You can easily keep two expressions on two separate lines. However, there are expressions that you cannot fit into a single line.
Here is an imaginarry example.

                                        
    ['^(([^<>()[\]\\.,;:\\s@\"]+(\\.[^<>(),[\]\\.,;:\\s@\"]+)*)',
    '|(\\".+\\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.',
    '[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\\.)+',
    '[a-zA-Z]{2,}))$'].join('')                 
                                    

For such scenarios, Scala allows you to extend long expressions to multiple lines. The compiler is smart and it will try to combine them and interprate it as a single expression. However, it is not always possible for the compiler to correctly interpret a multi-line expression. So, I recommend you to enclose it within a pair of parenthesis. An opening parenthesis will force the compiler to look at the next line until it finds the closing part. In that case, the compiler processes everything within the bracket at once.

Return Keyword

The return keyword is optional. You might be wondering, How Scala knows that what should it return? The answer is simple.
If there is no return keyword, Scala function returns the value of the last executed expression. Scala recommends you to avoid multiple endpoints in a function. In an ideal scenario, your function should have a single exit point, and that should be the last expression of your Scala function.
We have a simple example as shown below.

                                        
    def myMax(x:Int, y:Int) : Int = {
        if (x > y) 
            x
        else 
            y
        }                 
                                    

The If expression is the last expression of this function. When the condition is true, the If expression returns x else it returns y.


Curly Braces

Let's take the example shown above. We can squeeze the code further, and it looks as shown below.

                                        
    def myMax(x:Int, y:Int) : Int = {
        if (x > y)  x  else  y
        }                 
                                    

When you have a single expression in the function body, you can also leave the curly braces. So the code looks as below.

                                        
    def myMax(x:Int, y:Int) : Int = if (x > y)  x  else  y                    
                                    

Return Type

Scala compiler is smart enough to infer the return type of a function in most of the cases. So, whenever Scala can infer the return type of a function, the return type is also optional. Now the code shown above looks like as below.

                                            
    def myMax(x:Int, y:Int) = if (x > y)  x  else  y                    
                                        

These type of single line functions and methods are standard in Scala. You will often see them. You will also see multi-line functions in Scala. However, they will have a pair of curly braces around the body.

The = symbol

You might be wondering that if so many things are optional, isn't the = symbol optional?
When you have a pair of curly braces around the function body, the = symbol is optional. However, the recommendation is to avoid removing the = symbol. I mean, you should always use the = symbol to separate the function definition and the body. If you remove the = symbol, the compiler assumes that the function is returning a Unit. Your compiler may or may not give you a warning. However, it will infer the return type as a Unit even if you are returning something else. So, do not remove the = symbol.


The ( ) symbol

Let's start with an example.

                                                
    def hWorld() = println("Hello World!")                    
                                            

The above function does not have any parameters. Can I remove the parenthesis?
Before I answer that question, let me ask you another question.
Do you know, how many ways you can call the above parameterless function?
There are two ways to call it.

                                                
    hWorld()
    hWorld                    
                                            

You can call a parameterless function with a parenthesis and without a parenthesis as shown above. Now let's come back to our original question.
Can I remove the empty parenthesis?
Yes, you can remove the empty parenthesis at the time of defining a function. However, if you do that, you will not be able to call the function with a pair of parenthesis. The example below clearly shows it.

                                                
    def hWorld = println("Hello World!")
    //hWorld: Unit
    
    hWorld
    //Hello World!
    
    hWorld()
    //error: Unit does not take parameters                   
                                            

Now we have another question. Which one should we use?
There is no rule. However, we follow these conventions.

  1. When the function has a side effect, define it and call it with a parenthesis, even if it does not have any parameters.
  2. When the function does not have a side effect, and it does not have a parameter, you should define it and call it without parenthesis.

A parameterless function with a parenthesis indicates a side effect. It will help you and others to read your code.
Continue reading to understand more concepts.

Read More

Basics of Scala functions | Function Literals in Scala | Function values | Local Functions | Variable length argument | Default values and named arguments | Scala Placeholder syntax | Higher Order functions | Partially applied functions | Function currying

By Prashant Pandey -


You will also like:


Scala Variable length arguments

How do you create a variable length argument in Scala? Why would you need it?

Learning Journal

Local Functions

How do you implement private methods in a functional programming language.

Learning Journal

Referential Transparency

Referential Transparency is an easy method to verify the purity of a function.

Learning Journal

Statements and Expressions

Statements and Expressions in Scala. How are they different?

Learning Journal

Lazy Evaluations

Evaluate the expression now vs evaluate it for the first use. Strict vs Lazy?

Learning Journal