Thursday, August 13, 2020

Add Functional Programming to Object-oriented Programming, not the other way round

The programming world has multiple paradigms, or styles of programming. The reigning champion is Object-oriented Programming, embodied in C++, Java, and C# and oriented around, well, objects. The prior champion was Structured Programming (or Procedural Programming) represented by C and Pascal and oriented around control structures (and avoiding GOTOs). The challenger is Functional Programming oriented around functions, and in the languages Haskell and F#, among others. An older paradigm is Unstructured Programming (USP), which does use GOTOs and lacks the modern IF/THEN/ELSE and DO/WHILE constructs of Structured Programming.

SP and USP operate in the same space: small and medium-side programs. Since they operate in the same space, one often picks one of them, but does not use both. (One can use both, but it is not easy.)

Object-oriented programming (OOP) operates in "the large" and helps us organize large systems. Structured Programming (SP) and Functional Programming (FP) operate in "the small" and help us build short blocks of code that are reliable and readable. In this view, SP complements OOP and they work well together. SP and FP, on the other hand, compete in the same space. We can build large systems with OOP and SP, or with OOP and FP. (We can build small programs with SP alone, or with FP alone. OOP is not useful with small programs.)

Structured Programming is demonstrably better than Unstructured Programming. Functional programming is arguably better then the older Structured Programming. One would think that we would use the best paradigm, and that we would use Functional Programming. But we don't. It takes time to learn a programming paradigm, and most programmers know the Structured Programming paradigm. Structured Programming is what we have, buried inside many modern systems.

The mix of Object-oriented Programming and Structured Programming makes sense. To use a programming paradigm, or a mix of paradigms, one must have a language that supports the paradigms. C++, Java, and C# all support OOP and SP. Pascal supports only SP; Object Pascal and Delphi support both. Haskell supports FP.

The advocates of Functional Programming have noticed that their preferred languages have achieved modest acceptance, but none have become as popular as the most popular languages C++, Java, and C#, or even Python. That lack of acceptance makes some sense, as a Functional Programming language does not have the Object-oriented Programming concepts that help us organize large systems. (Conversations with practitioners have probably ended with project managers and OOP programmers saying something along the lines of "Functional Programming is nice, but we have a large code base in an Object-oriented Programming language, and we cannot give up that organization." 

I think these conversations have spurred the advocates of Functional Programming to merge OOP into FP languages, the hope that project managers and programmers will accept the new combination. The combination of object-oriented programming and functional programming is a nice trick, and it works.

But this approach is, in my view, the wrong approach.

When programmers and managers say that they want a programming language that supports OOP and FP, they don't really mean that they want an FP programming language that supports OOP.

What they want is a programming language that supports their current code base and allows them to add Functional Programming in small doses.

They want a compromise, much like C++ was a compromise for OOP. C++ offered classes to C programmers -- and was originally called "C with classes". It didn't mandate a pure OOP approach. Instead, it let programmers add OOP to an existing code base, and add OOP in a gradual manner.

The "FP plus OOP" approach fails because the existing code base is not OOP, but OOP with SP. A "FP plus OOP" language requires that all of the SP code blocks be re-written in FP. That can work for tiny programs and classroom exercises, but it doesn't work in the industry with large sets of code.

Yes, some companies have large, million-lines-of-code systems written in FP. But those systems were built in FP from the beginning.

Companies that have large, million-lines-of-code systems written in OOP (with procedural code too) don't want to stop everything and re-write that code. They want to add FP in small doses. They want the benefit of FP in a few key locations. Over time, they can expand FP to other parts of the system.

They don't want an FP language with OOP extensions. They want an "OOP and SP" language with FP extensions.

There is a language that may provide a path forward. Microsoft has its F# language, which is a Functional Programming language, but it also lives in .NET, which means one can combine F# modules with C# modules. If one has a system in C# and wants the advantages of Functional Programming, F# is worth investigating.

But beyond F#, I see no languages that offer a compromise between paradigms, and a way forward for managers and programmers. The current set of FP languages are too "pure" and don't allow the mixing of OOP, FP, and SP paradigms.

Perhaps we will see some new languages that bridge the worlds of Structured Programming, Object-oriented Programming, and Functional Programming.