Functional Scala

This is the fifth in a series of posts that walks through the experience of what it was like to go from being a veteran .NET developer with no awareness of the world beyond the borders of the CLR to exploring the mysteries of the Scala/Akka/Spray stack on the JVM.

The Functional Side of Things

Since Scala is a hybrid language it doesn’t just provide object-oriented programming capabilities. It’s also a fully-featured functional language as well. For a .NET developer who has spent his career in C#, this has been one of the most interesting parts of the learning experience.

What is a Function, Really?

While studying Scala the point was made that there are essentially two key concepts to functional programming. The first is that functions are treated as first-class. What that means is that a function is more than just a sequence of instructions, it’s a entity in its own right that can be stored and passed around like any other value. The second is the idea that any given function needs to be completely self-contained without side effects. I like the way Odersky puts it in Programming in Scala. He says that functions should be referentially transparent. I like this. Another way of putting it is that if I have a section of code that calls a function, I should be able to replace the function call with the function result and everything should continue to work as expected.

.NET Delegates and Scala Functions

In .NET, methods are anchored to the object they’re declared on and can’t easily be stored in a variable and passed around as arguments. Using a delegate, though, does allow me to create a type-safe method pointer that can be passed around. For example, suppose I have a utility class that provides static methods for manipulating numbers. If I want to conditionally apply one of those methods as a function in an unrelated class as a method argument, I need to jump through a couple of hoops. First, I need to declare a delegate that describes the signature of the method I want to store, then I need to create an instance of the delegate for each utility method I want to use, and, finally, I can pass the delegate instance to my target method. For example:

namespace Start 
{ 
    using System; 
    using System.Collections.Generic;

    public delegate int Calculator(int number);

    public static class Utilities 
    { 
        public static int Double(int number) 
        { 
            return number * 2; 
        }

        public static int Increment(int number) 
        {
            return ++number; 
        } 
    }

    internal class Program 
    { 
        private static void Main(string[] args) 
        { 
            Calculator doubler = new Calculator(Utilities.Double); 
            Calculator incrementer = new Calculator(Utilities.Increment); 
    
            int number = 4; 
            int result = number % 2 == 0 ? 
                Program.ManipulateNumber(number, doubler) : 
                Program.ManipulateNumber(number, incrementer); 

            Console.WriteLine("The number is {0}.", number.ToString()); 
            Console.WriteLine("The manipulated number is {0}.", result.ToString()); 
            Console.ReadLine(); 
        }

        private static int ManipulateNumber(int n, Calculator op) 
        { 
            return operation(number); 
        } 
    } 
}

/* 
If the value of _number_ is even (4) then the program outputs: 
    The number is 4. 
    The manipulated number is 8.

Whereas, if the value of _number_ is odd then the program outputs: 
    The number is 5. 
    The manipulated number is 6.
*/

Following the .NET example requires a certain amount of ceremony to get things setup before I can use the delegates. Scala, on the other hand, doesn’t require any kind of setup. Here’s the same example using Scala:

object Utilities { 
    def double(n: Int): Int = {
        n * 2 
    }

    def increment(n: Int): Int = { 
        n + 1 
    } 
}

class Program { 
    def main() = { 
        val number = 5 
        var result = 0

        if(number % 2 == 0) { 
            result = manipulateNumber(number, Utilities.double) 
        } else { 
            result = manipulateNumber(number, Utilities.increment) 
        }

        println(s"The number is $number.") 
        println(s"The manipulated number is $result.") 
    }

    def manipulateNumber(n: Int, op: Int => Int): Int = { 
        op(n) 
    } 
}

The main difference between the two versions is that Scala treats the function as first-class. In the method signature there’s the argument op that is defined as a type Int => Int. This is a Scala construct that, essentially, states that op is a function that accepts an Int parameter and returns an Int result. Using this syntax, I can pass the double or increment method of the Utilities object without any additional ceremony. I just do it.

.NET lambdas are a much closer match to the functional programming model than raw delegates. As a final example, here’s the program again using .NET lambdas:

namespace Start { 
    using System; 
    using System.Collections.Generic;

    public delegate int Calculator(int number);

    internal class Program 
    { 
        private static void Main(string[] args) 
        { 
            Calculator doubler = x => x * 2; 
            Calculator incrementer = x => ++x;

            int number = 5; 
            int result = number % 2 == 0 ? doubler(number) : incrementer(number);

           Console.WriteLine("The number is {0}.", number.ToString());
           Console.WriteLine("The manipulated number is {0}.", result.ToString());
           Console.ReadLine(); 
        } 
    } 
}

This version is certainly more terse since I’ve been able to get rid of the Utilities class and the ManipulateNumber method. By using the lambda expressions I can store the function in the Calculator delegate instance and call the delegate directly.

In all the cases presented here, the conditions for functional programming have been satisfied in that the functions in question (the double and increment methods) are treated as first-class as evidenced by the ability to pass them as method arguments and they’re referentially transparent in that they don’t generate any side-effects when run. Both methods are completely self-contained and only operate on the inputs received.