A Taste of Kotlin and Functional Programming

Kotlin is a programming language targeting the Java platform. It is being used by more than 60% of android developers. Kotlin is concise, safe pragmatic and focused on interoperability with Java code.

Kotlin beholds fourth place among the fastest-growing programming language on several renowned indices. Some of the prominent features of Kotlin are:

  • Concise code and structured concurrency.
  • Enhanced security features.
  • Coding is approximately 20% less as compared to Java.
  • It is 100% interoperable.
  • Companies working on Kotlin are Pinterest, Uber, Trello, Amazon, etc.

Kotlin, along with most other modern programming languages, is a multi-paradigm language. That means a program written in Kotlin can follow one or more of several programming paradigms, including Functional, Procedural and Object Oriented.

In the following post, I’d like to examine a few syntaxes and patterns of the Kotlin programming language. It is not a tutorial, but rather a flavour of the Kotlin language and functional programming.

Functional Programming Quick Overview

Although the Functional Programming paradigm has only recently begun to be adopted, it was the first programming paradigm to be invented. Functional programming is a result of the lambda calculus – a formal system in mathematical logic that was introduced by Alonzo Church in the 1930s. Church invented l-calculus while pursuing the same mathematical problem that was motivating Alan Turing at the same time.

A fundamental concept of l-calculus is immutability – the notion that values of symbols do not change. Another fundamental notion – in both f-programming and l-calculus – is higher-order functions, functions that are either used as the inputs or returned as outputs from other functions.

Functional programming is based on a simple premise: constructing programs using only pure functions.

The term pure function imposes the following properties:

  • spaThe function return values are identical for identical arguments.
  • spaThe function application has no side effects.

In practice, these two properties mean almost the same thing, both tell us to avoid imperative programming practices of using local static variables, non-local variables and mutable references. Additionally, these two “laws” are avoiding input/output streams, since streams are mutable and have both, side effects and different return values on the same function call.

Functional Programming by Example

One of the best ways to showcase the difference between OOP to FB is demonstrating it by code. In the Clean Architecture book, Robert C. Martin uses a simple problem to demonstrate the differences:

Printing the squares of the first 25 integers.

In imperative style, using Java the program will look something like this:

In Clojure (declarative) which is a functional and dynamic dialect of Lisp, this might look as follow:

The Clojure syntax might look a bit strange at first, but once you get used to it, it makes sense.

The range function returns a never-ending list of integers starting from 0. This list passes into the map function, which calls an anonymous function with parameter x on each element, returning x * x. The list of squares passing into the take function returns a new list with only the first 25 elements. Finally, the println function prints its input, which is a list of squares of the first 25 integers.

Both of the functional programming properties are satisfied by the Clojure implementation as we don’t have any mutable variable, such as we have in the Java implementation the index variable i. Instead, in the Clojure program, we have a variable x that once initialized, is never modified.

This leads us to a surprising statement: Variables in functional languages do not vary.

Robert C. Martin – Clean Architecture, Pearson Education, 2018, p. 73.

Another thing to notice is that in the Clojure program, functions have a first-class citizen role, they don’t need to be warped by a class. Besides that, the (println) function takes other functions as arguments such as take and range, and take gets map as an argument which gets the anonymous inner function(fn[x](* x x)).

Kotlin and Functional Programming

One of the core assets of the Kotlin language design is to relax Java’s restriction of allowing static methods and variables to exist only within a class body. Instead, Kotlin functions can live at the top level of the package without needing a redundant class level.

Kotlin functions are first-class, which means they can be stored in variables and data structures, and can be passed as arguments to and returned from other higher-order functions. You can perform any operations on functions that are possible for other non-function values.

Kotlin documentation

Higher-order Functions and Lambdas

Kotlin has different syntax ways to pass anonymous functions and lambdas as a parameter:

This is probably the most basic implementation of lambdas in Kotlin, its syntax is very similar to a callback function. While callback functions can be either anonymous or named, lambdas are anonymous. In fact, lambdas are the functional way to implement callbacks.

Following is another example to point the difference between impertative and declartive programming:

Given two arrays of strings a1 and a2 return a sorted array r in lexicographical order of the strings of a1 which are substrings of strings of a2.

Codewars

Imperative – Procedural

Declarative – Functional

The imperative program is a function called inArray, which takes to arrays of strings as parameters. First, it initializes a variable r of an empty array, then it initializes inside the first for loop, the variable str. Next, the variable str1 inside the second for loop. Then, check if str1 contains str and if it does not exist yet on the initialized array r it adds add. Finally, it returns the sortedArray function value of r.

The declarative program executes the same algorithm but without mutable variables. Instead of looping with for and appending proper elements to r, the toTypedArray() function is called on the sorted() returned value which called on distinct() returned value which is called on the array1.filter result that is a collection of elements that passed the conditions of its lambda.

In terms of complexity, both implementations are running in quadratic time, but the benefits of the declarative implementation are avoiding possible race conditions, deadlock conditions and concurrent updates problems which are all related to mutable variables. You cannot have a race condition or a concurrent update problem if no variable is ever updated. You cannot have deadlocks without mutable locks.

Data Classes, Constructors and Methods

It is not unusual to create classes whose main purpose is to hold data. In such classes, some standard functionality and some utility functions are often mechanically derivable from the data. In Kotlin, these are called data classes and are marked with data:

Kotlinlang docs

As already mentioned, this post is not a tutorial, rather a high-level view of the Kotlin feature. To emphasize the Kotlin way of writing a class I’ll be using the Point class – a basic student’s task which goes as follow:

The Point class represents a 2-dimensional point in the euclidean space and has the following properties:

  1. Private variables x and y of type double representing the coordinates of the point.
  2. A copy constructor.
  3. Get x – returns the x coordinate.
  4. Get y – returns the y coordinate.
  5. Set x – sets a new value for the x coordinate.
  6. Set y – sets a new value for the y coordinate.
  7. To string – returns a string representation of the point.
  8. Equals – takes other point as input and returns ture if other equals to this, otherwise returns false.
  9. Is above – takes other point as input and returns true if this point is above the other, otherwise returns false.
  10. Is under – dose the same as above but true if under and otherwise false.
  11. Is left – …
  12. Is right – …
  13. Distance – takes other point as input, returns the distance between this point and other.
  14. Quadrant – returns the quadrant in which the point lies.

Implementing this using Java should look something like this:

The Kotlin implementation would look as follow:

Much shorter! isn’t it? and it does exactly the same things.

If you ask yourself where is the copying constructor or where are the toString and equals methods, so the Kotlin compiler automatically derives these class members for data classes.

chevron_left
chevron_right

Leave a comment

Your email address will not be published.

Comment
Name
Email
Website