Moving to kotlin, the question can arise: “should I program in OOP (Object Oriented Programming) style, or move to Functional programming?”. This page examines reviews what Object Oriented programming really means, what functional programing is, and outlines how there is no incompatibility if the correct approach to OOP is in place, and the two paradigms are best when combined.
- Functional Programming vs Programming using Functions
- OOP programming vs Non OOP programming
- Functional vs OOP: No Contest
- Misguided OOP vs the OOP/FP combination
Functional Programming vs Programming with functions.
What is FP?
Almost all modern programs use functions, but just using functions is not Functional programming. What is required is functions that are ‘functional’ in the mathematical sense, not programming in the ‘using functions’ sense. A mathematical function, or ‘pure function’ operates on the supplied arguments and returns a result and does nothing else. No ‘side effects’. Nothing changed by the function, no internal variables altered that will result a future call of the same function dealing with different values.
The best test for a ‘pure function’ is: will the result, and all aspects of calling the function be identical every time the function is invoked?
Limitations of ‘pure’ Functional Programing.
Any ‘side effect’ of calling the function disqualifies the function from being a ‘pure function’, as the only output from the function is the result of the function. The reality is a program without any ‘side effects’ is actually useless, as input/output is generally a side effect. The answer can to a problem may be able to be calculated using ‘pure functions’, but actually showing the answer is going to require input/output. So while a program may incorporate ‘pure functions’, no program will be entirely functional program. The second important point is that ‘pure functions’ can be built in any language.
Languages that supports functional programming give tools to make it easy to see what code will qualify as a ‘pure function’, and what does not.
OOP vs non OOP programming.
What is OOP?
OOP means different things to different people. To some the ‘class’ statement is the essence of object oriented programing, yet while ‘javacript’ has no class statement, but supports object oriented programming.
A more useful view of object oriented to think of ‘classes’ simply as ‘types’. A type permits operations on that type. These operations are ‘methods’ of that type, that is computing that can be done with that type. When different types (e.g. ‘int’ and ‘string’) each have their own interpretation of the same operation (e.g ‘+’ or plus) then we have one of the anchors of being object oriented: polymorphism. As almost every language has several different types which each have their own version of ‘+’, if follows that every language has some elements of object oriented. The core concepts of object oriented is present in almost every program, but object oriented programing is more than just some exposure to the concepts. An object oriented program does not just use the type system and which will already have some degree of object oriented approach, rather, and object oriented program extends the type system creating its own ‘types’ or ‘classes’. Further, a an object oriented program, is about using this approach as the basis of the solution.
The limitations of pure Object Oriented
Pure object oriented is usually stated to have four ingredients:
- polymorphism: the ability of different classes to effectively all act the same in some way but implementation their own version of one or more functions or operations to operate in an equivalent way
- encapsulation: the implementation of the class (or type) is coded within the class and code using the class has no need to consider how the class is implemented and will not be impacted if the implementation changes
- inheritance: classes or types can inherit or ‘sublcass’ from a ‘superclass’. This enables both reuse of code, and is a key tool for building polymorphism when more than one class subclasses from the same parent has its own implementation of the methods of the superclass
- abstraction: this is giving the class an interface designed around the logical use of the class, and not simply a reflection of the mechanics of the underlying code
Of these four usually quoted points, all but one are mostly about techniques to do OOP well, while encapsulation is really a test of OOP or not OOP. ‘Pure’ OOP code be built from purely from Objects with the code encapsulated within the classes.
The language Java provides a perfect illustration of why ‘pure’ OOP is a mistake. Where efficiency dictates, the despatch tables within classes required for encapsulation are a performance killer. For performance. low level, close to the computer objects are best being reduced by the compiler to direct inline code. This does not stop such low level object classes adhering to the object model, or at least linguistically, being objects. However Java even goes as far a simply dropping all pretence of objects, or Object Oriented code for ‘native types’. In contrast to Java itself, the Java must write all code in classes. The simple example of the ‘hello world’ which results in a pointless class wrapper containing the ‘main’ method, illustrates how even enforcing there are classes, does not create an Object based approach, and that for some code, there is no object based approach.
In python, a programmer could implement their own class system using dictionaries of methods and properties. But creating new objects requires allocating memory, keeping track of when an object is no longer needed and freeing that memory. In fact some ‘object oriented’ languages (like c++) require programs to manually control garbage collection (returning memory to ‘free memory’ when objects are no longer needed). Every feature needed for OOP can be implemented with no special features at all, however is most languages ‘DIY’ would be laborious and distract from the application. No special feature is needed to do OO, but to do OO well, a good syntax and feature set is essential.
Functional vs OOP: No contest!
The optimal FP approach, is avoid side effects wherever possible. The optimal OOP approach is for all data in the program to be an object. FP sounds like focusing on the purity of the logic steps, OOP is about focusing on the data. But FP programs still need data, and operations on data, and regarding that data as objects and empowering the data makes sense. There is no problem combining both paradigms in a single program.
Some argue that the OO philosophy encourages programming in a ‘state-driven’ manner that is the antithesis of FP, but this argument ignores the foundations of the best FP languages have OO based type-systems.
OO itself makes it easy to break FP principles, but also can make it easy to follow FP principles. Kotlin does give more tools to support using OO together with FP style than python does, but this can be done with either language. As a simplistic example, a ‘val’ in kotlin is a variable which can never be reassigned, with python a programmer can still have variable which is never reassigned, but the programmer will need document this and check themselves that the rule is followed.
Misguided OOP vs the OOP and FP combination.
Recently, I was speaking with a programmer who declared, “Object Oriented is dead, Functional Programming is the correct way!” He had a link to a video describing how OOP programs could break all the principles of FP. OOP programs that behave this way are simply bad OOP programs! I have not found that video again, but I can recommend this (rather long) video by ‘uncle’ Bob Martin on functional programming (see 50:00 minutes in for the points on OOP with functional programming). Misguided OOP tries to force everything, including functions, into objects. A classic example of this is with Java where even the main function of a program has to be wrapped within an object that adds nothing. Kotlin moves from the misguided OOP of Java in many ways, for example by making functions first class objects. As this guide progresses, the theme of Kotlin adapting true, more mature OOP into the system, and in a Functional Programming compatible way, while still maintaining java compatibility, is repeated over and over.