Class Level Objects, Companion Objects & Instances

Topics for this section:

  • Class Level Objects & Companion Objects:  Key Terminology.
    • the simplest case – one object type
    • Python – an additional object type requires precise terminology
    • Kotlin: the companion object equates to the Python class object
  • Class & Companion Variables and Methods vs instance methods and variables
  •  Terminology for Clarity: Class Level Object, Variables and Methods
  • instance vs class variables in python
  • an alternative explanation of instance vs class for python

Class Level Objects & Companion Objects: Settling on Terminology

This bliki assumes a reader has knowledge of what class is, and what is an object is, but precise usage of the terminology does change from language to language, so please  tolerate a review of very basic concepts in order to be specific about exact terminology

Consider a Person class, that will have two instances, one for “Jack” and one for “Jill”.

The simplest case: the base of confusion

With a compiler language, the compiler will read the class definition and generate the code for all methods required by the class.  The compiler will also store in an internal data structure of the compiler all relevant information about Person class.  For any code relating to the class, the compiler will use the information it has stored about the class to enable generation of the appropriate code.

At run time the Jack and Jill instances Jack and Jill of the person class are created.  So there are two object, both instances of same class: the Person class.  In this environment, any reference to a Person object must be a reference to the Jack or Jill instances.

Python: An additional object type requires precise terminology.

Now consider Python.  The python language also builds the internal data structure containing the relevant information about the person class, and in fact that data structure is an object of the ‘type’ class.  But with python, there is not the same distinction between compile time and run time.  The running program can also access the ‘internal data structure’ – which in fact makes it no so internal.  At run time, there will be an instance of the type class : Person, and once Jack and Jill are instanced, there will be two instances of the Person class: Jack and Jill.  As there is only one Person class regardless of how many instances of Person are generated,  there will always be one Person class level object, regardless of whether there are zero or one hundred instances.  So with the Jack and Jill example with python, there are now three objects available to the running program.  A type object: Person, and two Person Objects: Jack and Jill.  When we say ‘Person object’, do we mean the object describing the class, or one of the two objects which are instances of the class?

In python, the convention is that the object describing the class is the class, and a class variable is a variable within that object describing the class, as opposed to a variable within an instance of the class such as Jack and Jill.  The variables within these instances are instance variables.  This contrasts with the previous simple case, where, with only one instances type of object for any class, the term class variable can only mean an instance variable.

Kotlin: The companion Object equates to the Python class object

Kotlin also provides for an object holding data at the class level, the companion object. Unlike Python, not all classes have a companion object.  Classes with a companion object at class level, must specifically declare a companion object. Keeping the companion object as optional allows the metaprogramming power of Python, or the closer to C++ internal simplicity of Java.

Like the Python class object, there is one companion object for a class, regardless of how many (or even any) instances of the class are created.

Class & Companion Variables and Methods vs instance methods and variables

Variables.

With Kotlin, the developer can declare variables within the companion object, and with Python class variables can be declared at class level.  In both cases, the provides a single variable shared by every instance of the class, and accessible even without the need for an instance.

Java and several other languages have static variables, which have the same property of  a single shared variable regardless of instances of the class and the possibility of access independent an any instance.   However,  there the key difference is with Python and Kotlin, this shared variable is also contained in an object, while a static variable has name scope within a class, but beyond that name, there is no relationship between a static variable and any object.  An example of this difference is that a companion or class object can be part of a family of related classes and implement an interface or have inheritance or duck typing, allowing passing the object as parameter allowing code to operate on the class/companion variable without knowing the specific class.

Simply put, the companion/ class level object is a more object oriented approach that supports more metaprogramming.

Methods

Python supports both class methods and static methods.  Static methods being an equivalent to other static methods in that they have name scope, but have no other relationship with any object.

Kotlin has companion object methods with are similar to python class methods, in that they have access to the object containing all settings, class variables and methods.  They are just like instance methods, but operation on a companion type, or type object, in place of operation on an instance of the class itself.

Terminology for Clarity: Class Level Object, Variables and Methods

The python term ‘class method’ or ‘ class variable’ has a very high protentional for confusion with regular instance variables or instance methods.

The proposal current in use within this bliki is to use the term ‘class level method‘ or ‘class level variable‘.  Another contender in place of ‘level’ was ‘singleton’ but the simpler level is the choice…at least for now.

 

Advertisements

OOP vs Functional: No contest!

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 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.

Language requirements.

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.

Language Requirements.

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.