An Introduction to Functional Programming with Scala

In computer science, Functional Programming is a programming paradigm where programs are constructed by applying and composing functions. In this article, we explain what makes Scala unique as a programming language and why it is ideal for today's highly scalable, data-centric applications.

Why Functional Programming Matters

Well-structured software is easy to write, easy to debug, and provides a collection of modules that can be re-used to reduce future programming costs. In his paper ‘Why Functional Programming Matters’, John Hughes points out that the problems we solve with software are becoming more complex with the passing of time. They require a more practical way to be tested, and a more efficient approach to writing them. The Functional Programming paradigm helps greatly in both these respects.

Even more importantly, this paradigm is a natural for parallelism. For several years now, gains in Central Processing Unit (CPU) raw speed have been modest. Nevertheless, systems have been getting faster by adding more cores which run in parallel.

Why Scala?

Although there are multiple multi-paradigm languages available, Scala combines object-oriented and Functional Programming in one concise language. Today, it is one of the most widely utilized languages by the functional community, up to par with F#, Haskell, and Clojure, a.o.

At Encora, we are big fans of Functional Programming and Scala for the following reasons:

The language is versatile and the combination of features makes it possible to write programs that are concise, elegant, and easier to debug and maintain than many other programming languages.

Scala is executed on a Java virtual machine (JVM), and provides interoperability and compatibility with Java, Groovy, Clojure, etc. This allows developers to keep their libraries and leverage the advantages of JVM.

Scala is easier to debug and maintain than many other programming languages, it’s maintenance is simply much faster.

Within recent years an increasing number of companies have switched to both Functional Programming and Scala, including tech giants such as Twitter and LinkedIn. In 2020, Scala made it to the top 10 languages that developers want to learn, further proving its popularity.

Pure Functions

A pure function depends solely on its inbound parameters and should only return a specific result without mutating an outer condition within its reach. A good example of a pure function is simply based on the parameter it receives and it offers a result.


def sin(value: Double): Double

Non-pure Functions

Non-pure functions allow external/internal context modification. Pure functions are easy to test and predict. However, sometimes it’s necessary to do something that modifies state, like writing a file, or updating a table within a database. That’s why non-pure functions exist. For example,


def writeTofile(fileNameL String, text: String): Unit
def insertToDB(user: User): User

High Order Functions

One of the most powerful traits of Functional Programming are high order functions. They can take values or functions and return other values or functions;

  • take a function, return a value
  • take a value, return a function
  • take a function, return a function

class List[T]{
	// This Function takes another Function called "fn" as a parameter
    // that it's applied to each of the elements within the List
    // and filters then if "fn" returns false for that element.
    def filter[T](fn: T => Boolean): List[T]
}

val list: List[Int] = // ... initialized with [1, 2, 3, 4, 5, 6, 7, 8, 9]
var odds: List[Int] = list.filter(v => v % 2 != 0)
// returns: [1, 3, 5, 7, 9]

These functions not only shorten the programs, but also help produce cleaner code.


def isOdd(valor: Int): Boolean = {
	valor % 2 != 0
}

// let's define how we're going to filter
// this list using isOdd Function
val odds: List[Int] = list.filter(v = isOdd(v))
// returns: [1, 3, 5, 7, 9]

Immutability

Immutability refers to the data within an object that cannot be modified once it has been created. In Functional Programming, we don't change objects in our functions, we pass them into other functions to be manipulated. Immutability helps preserve the ability to compose things.

Of course, it’s not always possible to use immutable states, but designing the programs based on this premise is always highly recommended.

These examples contrast the advantages offered by Scala against an Object-Oriented language like Java,


// Java
// ... imports
public class Car {

	private final String _color;
    private final String _model;
    private final String _bran;
    private final Date _year;
    
    public Car(String color, String model, String brand, Date year) {
    	_color = color;
        _model = model;
        _brand = brand;
        _year = year;
    }
    
    public string getColor() {
    	return _color;
    }
    
    public String getModel() {
    	return _model;
    }
    
    public String getBrand() {
    	return _brand;
    }
    
    public Date getYear() {
    	return _year;
    }
}

// Scala

case class Car(color: String model: String brand: String year: Date)

Monads in Scala

A Monad is an interface that simply specifies one form for data composition. A Monad should be ruled by certain laws. Scala is not as strict with these laws, and its focus is more practical than anything.

From the language standpoint, the only traits that a Monad should have are the high-order functions flatMap and map. These provide the tool to compose the data they contain, through the application of a function. The following example further explains this:


class Monad[A](value: A) {
	//receives a Function 'f' that transforms any 'A' value into 'B' value
    def map[B](f: A=> B): Monad[B] = new Monad(f(value))
    
    //receives a Function 'f' that transforms any 'A' value into another 'Monad[B]'
    def flatMap[B](f: A => Monad[B] = f(value)
}

val firstMonad = new Monad(4)
val secondMonad = new Monad(6)

val resultingMonad = firstMonad.flatMap { x => 
	secondMonad.map { y => 
    	y + x
    }
}

// returns: Modan[Int] = 10

Imagine that every collection we know is a Monad (in Scala terms). This would mean that we are able to compose the internal data in this collection simply by applying a function through map or flatMap.


def x2(value: Int): Int = {
	value * 2
}

val lista = Seq( 1, 2, 4, 5, 6, 7, 8, 9, /*...*/ 100, 101 )
var listaX2 = lista.map { v => x2(v) }
// results: Seq( 2, 4, 8, 10, 12, 14, 16, 18, /*...*/ 200, 202 )

Key Takeaways

  • As software becomes more complex, more sophisticated development and maintenance methods are needed to establish structure and ensure quality.
  • Scala is a language that features full support of Functional Programming as well as the Object-Oriented Paradigm, making it one of the most widely utilized languages by the Functional community.
  • The combination of features in Scala makes it possible to write programs that are concise, elegant, and easier to debug and maintain than most other programming languages.
  • Some of the most important aspects of Functional Programming with Scala include pure functions, non-pure functions, high order functions, immutability, and Monads.

About Encora

Encora is a leader in the large and rapidly growing outsourced product development market. We create competitive advantage through accelerated technology innovation by providing companies with the required tools, talent, and processes. Our development teams are experienced with Functional Programming and know how to solve business problems using Scala. Do not hesitate to contact us if you have any questions, or if you would like to discuss your business needs.

Contact Us

Share this post

Table of Contents