Declaring Functions in scala

    A function is a piece of code that is designed to do some computation. It can be defined with no parameters or single or many parameters. It may return a unit(side effects- not recommended) or may return a value. It can be assigned to a variable in scala to store the value returned after computation.

    Basic syntax of a function:

    def nameOfFunction(functionParameter1 : ParameterType, …..): = ReturnType = {
        val result = // function Body
        result //If you notice we have not used return keyword here because it is not mandatory in scala
    }


    Note : A function which don't have ( := { <Body_of_Function> }) will be an abstract function

    There can be different type of functions:

    Anonymous Function :

    A function that doesn’t have a name are called Anonymous functions.

    Example:

    x: Int) => x + 1
    
    X is parameter to function and (x+1) defines body of function. To define more than one statement, we must enclose them in curly braces.
    (x: Int) => {
        val y = x+1;
        y*2;
    }

    Named Function

    A function which has a name is called Named function.

    Example

    val decrement = (number: Int) => number -1

    Here you can see we can assign a function to a value.

    Usage of the above example:

    println(decrement(5))    // this internally will evaluate like decrement.apply(5)


    All functions in Scala are special objects of type Function1 or Function2 or FunctionN, where N is the number of input arguments to the function. The compiler will box the function code we provide into the appropriate object automatically. This object contains a method apply() that can be called to execute our function.

    Methods

    It is a type of function that is part of a class, can be overridden, and can use a different syntax(overloaded). Scala doesn’t allow us to define an anonymous method. These are created using a special keyword “def”.

    Example

    def greetSomeone(name: String): String =   s"Welcome to + $name"
    
    greetSomeone("Techgeekbuzz!")

    Nested Method

    When a method is defined inside another method it is called a nested method.

    Example:

    def tailRecursiveFactorial(number: BigInt): BigInt = {
      def fact(number: BigInt, result: BigInt): BigInt = {
        if(number == 1) result
        else fact(number-1, number*result)
      }
      fact(number, 1)
    }
    tailRecursiveFactorial(10000)

    Higher Order Function

    A function which can be passed as a value to a function or a function that can be returned as a value from a function can be termed a Higher Order Function

    Example:

    map function defined on List is a higher order function. Syntax for the same is given below:

    final override def map[B](f : scala.Function1[A, B]) : scala.collection.immutable.List[B]


    List(1,2,3).map(_.*3)      // will give output :           List(3,6,9)

    Here[ _.*3 ] is a function which will multiply the element by 3. This function is passed into the map function and is an example of a higher-order function.

    Similar examples of the Higher Order function in the List class are below:

    override def filter(p : scala.Function1[A, scala.Boolean]) : scala.collection.immutable.List[A]
    
    override def partition(p : scala.Function1[A, scala.Boolean]): scala.Tuple2[scala.collection.immutable.List[A], scala.collection.immutable.List[A]] = { /* compiled code */ }