Immutability, a lack of side effects, and composability are some of the features that have recently increased the popularity of functional programming languages, especially in the era of microservices and cloud-native systems. Those core features also make it easier for developers to understand code by being able to reliably predict what a function will do. Testing small pieces that can then safely be composed together to create more complex behavior results in greater confidence in the code and improved reliability of the overall system.
The Resurgence of Functional Programming track at QCon Plus 2020 featured several experts describing how functional programming makes developing software a joyful experience. They also told why and how object-oriented languages such as C# and Java are evolving by becoming more functional.
The lead designer of the C# programming language, Mads Torgerson, described C#’s functional journey over nearly two decades. C# has always had functional capabilities, beginning with small ways to enhance object-oriented (OO) programming. Moving to the cloud and microservices necessitated functional additions to C#. Because data is often shared concurrently between many different applications, immutability becomes very important. Also, distributed systems need to separate state from functionality, but object-orientation combines state with behavior. Because of this, C# has evolved to make the functional paradigm easier. Torgerson said “we’ve tried to get rid of the tax on OO languages.”
Because adding features to a widely-used, general purpose language comes with a cost, programmers can expect to see some functional concepts slowly added to OO languages (C#, Java, etc.), but they are never going to replace pure functiona or functional-first languages (Haskell, F#, etc.). Rather than waiting for functional features to appear in the JDK, many developers are switching to more functional-friendly JVM languages, such as Scala, Kotlin, and Clojure.
James Ward and Josh Suereth, both from Google, showed code examples in Java, followed by samples in Kotlin and Scala, to highlight how functional programming makes code easier to understand and maintain. They suggested, “the hardest problem in OO programming is ‘how to construct an object,’ which you think would be easy.” If an object has many parameters, some of which are optional, you can end up with several constructors, a lot of code to maintain, and confusion about which constructor to call. One way to make this easier is the Builder Pattern, where another object is responsible for handling which constructor to call. While this makes one aspect of development easier, it effectively doubles the amount of code to maintain. Ward said, “With the functional evolution of OO, we’re seeing new ways of constructing objects,” then showed how case classes are used in Scala, allowing default parameters and named parameters. Similarly, Kotlin has data classes, and JDK 14 introduces record types.
By showing C# 1.0 code, then rewriting it using C# 2.0, 3.0, up to 7.0, Torgerson showed how each layer of new functionality was built upon the foundation of previous generations. In C# 1.0 syntax (see figure 1), he created a
Filter function that took a predicate to define the filtering rules for an array of integers. Introducing generics and the
yield statement (see figure 2) reduced the amount of code needed to produce the same result. Using LINQ’s
Where statement (see figure 3) meant the custom
Filter function was no longer necessary. He also added a
Select statement to show the ease of mapping the result to a new, anonymous type and the ability to chain functions together.
Figure 1: C# 1.0 code
Figure 2: C# 3.0 code
Figure 3: C# 3.0 code, using LINQ’s Where and Select statements
A reduced amount of code and increased readability were among the benefits Gene Kim spoke about while describing his love for Clojure. The author of The Phoenix Project, The DevOps Handbook, and, most recently, The Unicorn Project, praised Clojure as “good to think with,” a phrase coined by Claude Lévi-Strauss. For Kim, functional programming allows you to “solve problems, not solve puzzles,” and that can lead to increased focus, flow, and joy.
“The invisible structures of functional programming lead to focus, flow, and joy.” – Gene Kim
Figure 4: Lines of code comparison by Gene Kim
Pattern matching is another commonly heralded feature of functional programming. In C#, developers have always been able to use
switch statements to check an object’s type, but then had to do a subsequent cast to work with the typed object. Torgerson showed how C# can easily pass along the typed result of an
if statement (see figure 5), or perform pattern matching against a type and its properties (see figure 6).
Figure 5: C# Pattern matching passing along the cast string s
Figure 6: Advanced pattern matching in C#
Ward and Suereth used Kotlin to demonstrate pattern matching (see figure 7). They pointed out that not handling every possible case of a
when statement would result in a compiler warning, and recommended turning those into compiler errors. The advocates of functional programming say this is example of being able to catch an entire class of errors at compile time, leading to more predictable, reliable, and stable code.
Figure 7: Pattern matching in Kotlin
If he could wave a magic wand, Kim would want everyone to learn a functional programming language, so they could experience the same joy he has found. He also was pleased that The Unicorn Project, which reached #2 on the Wall Street Journal’s best-selling business books, meant that even non-technical business leaders were being exposed to Clojure.
As an online conference, QCon Plus featured speaker presentations, panel discussions, and in a nod to QCon conferences, a virtual hallway track, where attendees and speakers could continue their conversation. After his presentation on C#’s Functional Journey, dozens of attendees joined Mads Torgerson, where he explained how the team considers adding new features to the language. Adding something to C# has to overcome any of the negative aspects of it being there, and new ideas always start by being ranked with a deficit. Asked about his views on other languages, Torgerson said he loves Scala. He “wants to add functional features to C#, rather than creating a new language. C# is not trying to compete with functional-first languages like F#.”