Studies in object-oriented programming backbone implementations

This work is a combination of conceptual and hands on based study aimed at laying a foundation for practical ObjectOriented software construction. First it presents a conceptual study of a number of backbone concepts of modern Object-Oriented Programming (OOP) languages. Secondly, it attempts to demonstrate real-life implementations of these concepts using Python Programming Language. This work touches on practical issues on Class and Object Creation, especially on the syntax and creation, and demystifies the subject matter using a simple table of rules. The OOP concept of Inheritance was studied, with focus on the three major types of inheritance. The self-argument, and constructors were studied, with focus on the three constructors default, parameterized, and non-parameterized constructors. A brief discussion, and pictorial illustration was also made on the disparity between normal mathematical functions and OOP method calls. Further areas of studies are the concept of overriding between the parent and child class, as well as the OOP puzzle commonly known as Diamond Problem, including code segment and diagrammatic illustration of Python-based solutions. There are a number of other back-bone concepts in OOP not covered in this study, such as Encapsulation, Abstraction, Meta-Programming, among others, which will form areas of focus in future studies. Effort was made to enhance the overall presentation through practical illustrations using source codes, annotated diagrams, and discussions. It is hoped that this work will be very useful to researchers and other practitioners in Object Oriented implementations.


Introduction
Though Object Oriented Programming (OOP) [1] is considered to be a modern programming paradigm, the root goes back to 1967 when the first OOP language known as Simula 67 [2] was introduced. Understanding the relative strength of different programming languages in handling problems in different domains [3] is key. Different programming languages have their individual areas of strength and focus. In other words, their usage may vary drastically, depending on the type of problems being solved. A study of survey in programming languages [4] helps researchers to understand the strengths and weaknesses of different languages, and the choice of which paradigm fits which problems. Some of the major programming paradigms [5] are shown in Fig. 1. As shown in the figure, some of the major programming paradigms are imperative [6], object oriented [7], concurrency [8], functional [9], logic and event-driven [10] programming. This research focuses on Object Oriented Programming with the practical implementations based on Python 3.8. The choice of Python in this research is based on a number of its strengths and attributes. One of such attributes is the fact that Python is a multi-paradigm [11] programming language. This means, that it supports different programming approaches.

Figure 1 Major Programming Paradigms
Object Oriented Programming in Python focuses on creating reusable code, a concept commonly known as an acronym DRY (Don't Repeat Yourself) [12]. Again, the source code resulting from object-oriented programming is highly maintainable due to the modular approach applied. Moreover, program correctness could be enhanced in OOP since every class has a specific task. Thus, an error in one part of the code, could be rectified locally without having to affect other parts of the code. Some of the concepts to be studied and practically demonstrated in this work are Class, Object, Inheritance, Constructors, among others.

Class and object implementation
It is important to begin this section with a definition of the concept of Class [13]. In OOP, a class is a user defined blueprint or prototype [14] from which objects are created. In other words, a class represents the set of properties or methods that are common to all objects of one type. In practice, one of the first tasks at this point is to understand how to create a class. A Python Class is created using the following syntax: class ClassName: #Statement Suite As shown in the syntax statement, class creation involves using the keyword [15] class followed by the name of class, followed by a colon, then a suite of statements. There are important rules to be observed, to avoid syntax errors. These rules are enumerated in Table 1.

RULE 1
The keyword "class" should be in lower case, while the class name should start with a capital letter [16].

RULE 2
The statement suite (body of the class) consists of a number of statement types, ranging from fields (properties), constructors, functions, pass statements, among others, as will be further explained.

RULE 3
The body of the class starts on a new line, indented one tab from the left.

RULE 4
After creating a class, it has to be instantiated into objects.
Before a programmer can use a class, it has to be instantiated [17]. It is through this process that an object gets created from a class. The syntax to create the instance of the class is as follows: Where ObjName = name of the object being created. ClassName = name of the class being created arg = arguments.

Practical Illustration One
Fig. 2 depicts a practical illustration of the creation of a Python object called emp from the class Employee, where emp object inherited the fields (attributes) of the Employee class, and an assignment statement created using emp.name.

Inheritance implementations
The concept of Inheritance in OOP allows a programmer to define a class that takes and manifests the methods and properties from another class. The parent class is the class being inherited from, and this is also known as the base class [18]. On the other hands, a child class is the class that inherits from the parent or base class. Another name for the child class is the derived class [19].
There are three major types of inheritances supported by Python. These are Single Level Inheritance [20], Multi-Level Inheritance [21] and Multiple Level Inheritance [22], all of which will be illustrated in this work.
The general syntax for implementing inheritance is as follows: Child Class (Parent Class) Where Child Class = name of the child class.
Parent Class = name of the parent class.

Practical Illustration Two
Given that a Python program is made up of two classes called Sun and Moon. Create the two classes, then write a line of statement to show that Moon inherits from the Sun. The constructor method should be populated with a pass statement [23]. The source code for solution to this problem is shown in Fig. 3.

Figure 3
Code for Practical Illustration Two

Practical Illustration Three
A multiple inheritance design has eight classes A, B, C, D, E, F, G and H where B, C, D inherited A; E inherited B and C; F inherited B and D; G inherited C and D while H inherited E, F and G. The task to be accomplished in this regard is to draw the inheritance diagram, and to write a simple program to accomplish this. The first solution for this problem is shown in Fig. 4.

Figure 4 The Inheritance Diagram
The python code equivalence of the above diagrammatic representation [24] is shown in Fig. 5. As shown in the code segment, the class on the topmost hierarchy is class A, which was inherited by another class B. This is indicated by placing the parent A within a bracket under B. This thread continues, until the last inheritance statement, where H inherits from the parent classes E, F and G. The three major inheritance types are clearly annotated in the right-hand side (RHS) of the diagram. A single inheritance is a simplistic case, where one class inherits another, for instance B (A). In a multi-level inheritance, there is a trail of inheritance, with one giving rise to another, for instance C(A) followed by E(C), and so on. Finally, in a multiple inheritance case, a particular class inherits from multiple parents at the same time, for instance, H (E, F, G).

Figure 5
The Inheritance Source Code Fig. 6 is a code segment [25] having a given class and a single method. The class name is Example, which is followed by an indented block [26] of statements which represent the body of the class. The name of the method defined is test. There are a number of key observations in the source code illustration in Fig. 6. First is that it is usual for class methods to have an extra first parameter known as "self" in the method definition. In real life, the number of parameters [27] in a typical mathematical function definition is expected to tally with number of arguments in function calls [28]. But this rule is apparently defied in OOP implementations in Python. This syntactical variation is shown in Fig. 7.

The self-argument implementations
Thus, the first parameter is not given value (arguments) during method calls, but rather is usually provided internally by Python. There are a number of important points to bear in mind when implementing the self-arguments, some of which are itemized in Table 2: Table 2 Key Points on Self Argument

Point 1
Even if a method takes no argument during its call, a programmer still has to insert one parameter -the self -as shown in the last illustration test( ).

Point 2
The Point 1 above is similar to "this" pointer in C++ and "this" reference in Java.

Point 3
When the programmer calls a method of the object as myobj.method (arg1, arg2), this is automatically converted by Python into MyClass.method (myobj, arg1, arg2).

Point 4
In summary, it follows that self is a special parameter in Python [29].

Constructor implementations
A constructor is defined as a special method used for initializing the instance variables during object creation. A Python Constructor is usually implemented using __init__ (self) [30]. There are three major types constructors as shown in Fig.  8, though a number of researchers limit their interest to only two.

Figure 8 Three Types of Constructors
For a very unambiguous explanation of the implementation [31] of the three types of constructors, it is necessary to use some practical illustrations. The flow diagram shown in Fig. 9 shows how to implement a default constructor [32] The default constructor specifies default values in the Constructor definition, and at the same time, provides parameter equations within the __init__ method block. The flowchart [33] can be explained using the following IF statements: IF no arguments are specified while creating an instance of the class, THEN the default values set for the __init__() method parameters gets assigned to instance, OTHERWISE IF you specify arguments during instantiation, THEN the default values assigned to __init__() method parameters will be overwritten with the latest values. Having looked at the default constructor, it is important to mention that parameterized constructor [34] implementations come with explicit parameters, while the in non-parameterized [35] case, there are no explicit parameters, rather, the self-parameter is prominently featured. This research will give practical illustrations at this moment.

Practical Illustration Four
The aim of the practical illustration is to create a parameterized constructor for farm fruits. The parameter is called fruitname. The Fruit class has two other methods. The first one queries a person for the type of fruit he/she loves, and another responds with "I Love xyz" where xyz is the actual fruit name supplied as an argument to method invocation. The class should be instantiated accordingly. The solution is shown in Fig. 10.

Figure 10 Parameterized Constructor Solution
As shown, the solution has been annotated [36], with four arrows originating from the right-hand side (RHS) and pointing to the lines of the codes that represent definite solutions. Also, as shown in the comment section [37] of the first line of the code, the name of the python file is fruit_para.py.

Practical Illustration Five
The aim of the practical illustration is to create a non-parameterized constructor for farm fruits. As in parameterized case, the Fruit class has two other methods. The first one queries a person for the type of fruit he/she loves, and another responds with "I Love xyz" where xyz is the actual fruit name, defined within the constructor as an instance variable. The class should be instantiated accordingly. The solution is shown in Fig. 11.

Figure 11 Non-Parameterized Constructor Solution
As shown, the solution has been annotated, with five arrows originating from the right-hand side (RHS) and pointing to the lines of the codes that represent definite solutions. Also, as shown in the comment section of the first line of the code, the name of the python file is fruit_nonpara.py.

Practical Illustration Six
The aim of the practical illustration is to combine both parameterized and non-parameterized constructors to form default constructors to create a new Fruit class that makes use of Default Constructor. The default fruit name should be APPLE. The solution is shown in Fig. 12.

Figure 12
Default Constructor Solution

The concept of overriding
One of the important concepts in Object Oriented Programming is the overriding. This will be explained, and practically implemented as follows. A child class naturally inherits the methods and attributes of the parent class. However, if the child class has a method, which has same name as that of a parent class, but with a different definition/content, then the child's method is said to override [38] that of the parent. This is comparable to stubborn children who refuse to look like their parents/ancestors, but chose to be unique, strange and weird !

Practical Illustration Seven
The aim of this section is to create two Python Programs called b4overide.py and afteroveride.py respectively, so as to illustrate Overriding in Python. These are shown in Fig. 13 and Fig. 14. In the first code segment, there are two classes designated as King and Prince, where the child is naturally open to inherit attributes of the parent. However, in the second segment, the child overrides the parents. This is clearly activated using the action method, which gives two major outputs. These are "There is Trouble in the Land" and "The Small Boy Prince Overrides Papa King" respectively.

The diamond problem
Before concluding this work, it is important to explore what is usually known as the Diamond Problem, explain what it is all about, and state how it is solved. In doing this, four distinct classes A, B, C and D will be utilized, where A is the topmost in the hierarchy, and the contentious method is called "methodxyz".
A Diamond Problem [39] is an issue resulting from multiple inheritance of four classes in OOP as explained in the following scenario. If classes B and C inherit from A and class D inherits from B and C, and both B and C have a method called methodxyz. The issue then is, "Which of the competing methodxyz will D inherit?" This ambiguity is known as the diamond problem. A sample code as well as pictorial diagram to illustrate the Diamond Problem are shown in Fig. 15.
Different OOP languages resolve the diamond problem puzzle in different ways. In Python it is resolved using what is known as MRO (Method Resolution Ordering) algorithms [40]

Figure 15
Diamond Problem -Code and Diagram

Conclusion
This work has presented a conceptual and practical oriented study of Object-Oriented Programming (OOP). Effort was made to present a number of fundamental concepts, referred to in this work as the backbone concepts. The concepts covered are class and object creation, inheritance, constructors, mathematical and OOP method disparity, and the selfconcepts. Other backbone concepts covered are overriding between the parent and child class, the Damond Problem and resolution. In order to enhance understanding of this subject matter, about ten code segments were shown. There were also pictorial presentations, flow diagrams, among others. It is hoped that this work will be very useful to researchers and practitioners in Object Oriented implementations.