Tony Marston's Blog About software development, PHP and OOP

What is the difference between Procedural and OO programming?

Posted on 20th April 2017 by Tony Marston

Amended on 1st November 2022

Introduction
Your code is not OO, it is procedural
The ONLY differences between Procedural and OO
Encapsulation
Inheritance
Polymorphism
Abstraction is not a separate concept
They are the same except for ....
Not all OO code is good code
Conclusion
References
Amendment History
Comments

Introduction

I often read blogs about OOP in which various people discuss the merits of one theory/principle/pattern over another, or even how a particular theory/principle/pattern could be implemented, and there is one form of criticism which is becoming more and more prevalent:

If you don't do things the way that I tell you then your code is not OO, it is procedural.

When said in that way the words "your code is procedural", are a form of insult. They are saying that even though your code may be using objects, because you are not using them in the "proper" manner then it is not "true" OO code, it is procedural code which is pretending to be OO.

I consider this attitude to be a pile of bovine excrement, and in the following paragraphs I shall explain why.


Your code is not OO, it is procedural

Here are some of the criticism which I have found:

In Inheritance Is a Procedural Technique for Code Reuse the author says the following:

Inheritance is bad because it is a procedural technique for code reuse. .... That's why it doesn't fit into object-oriented programming.

Rubbish! Inheritance is one of the three characteristics which differentiates OO programming from no-OO programming, so saying that it doesn't fit into OOP just shows that you have lost the plot. Inheritance CANNOT be a procedural technique as it never existed in any procedural languages.

In Are You Still Debugging? the author says the following:

Code is procedural when it is all about how the goal should be achieved instead of what the goal is.

Rubbish. What you are describing here is the difference between imperative programming, which describes how the result should be achieved, and declarative programming, which describes what the program should accomplish. These concepts are entirely different from and unrelated to the procedural and object oriented paradigms. For an example of declarative programming you need look no further that the $fieldspec array that exists in every database table class and which describes that table's structure. This defines the rules that should be followed when any user input needs to be validated before being written to the database, but it does not execute those rules. The code which actually performs this validation can be found in a single validation object which is provided as part of the framework.

In the same article he also said:

A method is procedural if the name is centered around a verb, but OO if it is centered around a noun.

Rubbish. The dictionary definition of method is "a way of doing something", so the "doing" part should immediately signify that it is a verb. Each class in the business/domain layer is built around something which has properties (data) and methods (operations), so the "thing" part should immediately signify a noun. Classes are therefore nouns while methods are therefore verbs. The only exception would be where the object in question is not an entity (which has state) but a service (which is stateless). A service could be a transformer which transforms raw data into a particular format, such as HTML or PDF; it could be a parser, or a validator. In this case the class name would be an adjective while the methods are still verbs.

In this post a person called Fasda said the following:

The key you need to focus is THE WAY YOU THINK A SOLUTION.
In procedural you thinks solutions as writing a recipe, step by step. First do that, then that, and continue with...
In OO you think solutions as "people asking favors to others" -> Objects and Messages only.

I have already stated in a previous article that OOP is not about the passing of messages. The way that an object method is called is exactly the same as how a procedural function is called - it is always synchronous. In a true messaging system the activity requires the use of separate sendMessage() and receiveMessage() functions, and may be either synchronous or asynchronous.

In the same post he also said the following:

Try to use some pure OO language to stop thinking on IF, WHILE, FOR and all those keywords so common in procedural.

In If-Then-Else Is a Code Smell the author says the following:

In most cases (maybe even in all of them), if-then-else can and must be replaced by a decorator or simply another object.

The idea that you cannot use IF, WHILE, FOR, etc in an OO program is too ridiculous for words. Where have the alternatives for these constructs been documented? Do they even exist?

Fortunately there are some sane people out there who do not go along with this idea. In his article Pragmatic OOP Ricki Sickenger had this to say:

I have met programmers who believe that anywhere there is a conditional statement in OO code, there is cause to subclass, "because that is the OO way!". And they will defend it against any pragmatic reasoning. So anywhere you see an if/then/else or a switch statement, you should find a way to break the logic into separate objects to avoid the logic. The dogma here is that conditional statements complicate things and are not strictly OO, so they must be minimized and preferable erased.

In this post a person called Goop said the following:

What you fail to realize is that scripting the flow of control in order to solve problems is absolutely anathema to OOP.

Then how does control flow from one group of instructions in an object method to another? Do you just write a number of methods and let the machine decide in what order they should be executed? Do you construct a mass of ravioli code and throw it into the air and let control flow from one piece of pasta to another in a random sequence? If scripting the flow of control is not "proper" in OOP then can you explain how the Template Method Pattern is in the list of design patterns?

The worst idea of all came from Getters/Setters. Evil. Period. in which David West wrote:

Step one in the transformation of a successful procedural developer into a successful object developer is a lobotomy.

This tells me that OO programmers are just like procedural programmers, but with part of their brains removed.


The ONLY differences between Procedural and OO

While there are some features which are common to both the procedural and OO paradigms, there are some which only exist in OO languages and MUST be present in order to allow a language to be called Object Oriented. These features are Encapsulation, Inheritance and Polymorphism. Although many optional extras have been added since OO languages became popular, I consider them to be nothing more than embellishments which, depending on your point of view, are either Gilding the Lilly or Gilding the Turd.

However, it should be noted that simply having different features is not good enough. Neither programmers nor their employers will switch to using a different language unless there is some benefit in doing so. The supposed benefit of OOP, as I have previously stated here, is that it "increases code reuse and decreases code maintenance". I say "supposed" for the simple reason that far too many programmers are following a corrupted set of "rules" which cause them to fail to meet this simple objective.

Encapsulation

Encapsulation The act of placing data and the operations that perform on that data in the same class. The class then becomes the 'capsule' or container for the data and operations. This binds together the data and the functions that manipulate the data.

More details can be found in Object-Oriented Programming for Heretics

OO languages have the following characteristics:

This is demonstrated in the following example:

$object1 = new foobar;
$object2 = new foobar;
$result1 = $object1->method1(...);
$result2 = $object1->method2(...);
$result3 = $object1->method3(...);
unset($object1);
$result1 = $object2->method1(...);
$result2 = $object2->method2(...);
$result3 = $object2->method3(...);
unset($object2);

Here you can see that each object is available for method calls between its instantiation (using the "new" keyword) and its destruction (using the "unset" keyword).

Procedural languages have the following characteristics:

This is demonstrated in the following example:

$result1 = function1(...);
$result2 = function2(...);
$result3 = function3(...);

Inheritance

Inheritance The reuse of base classes (superclasses) to form derived classes (subclasses). Methods and properties defined in the superclass are automatically shared by any subclass. A subclass may override any of the methods in the superclass, or may introduce new methods of its own.

More details can be found in Object-Oriented Programming for Heretics

In order to make use of the code sharing technique called inheritance you must first define the properties and methods which are to be inherited. This is called an abstract class. Then you can create any number of concrete classes which merge this definition with more specific details. This is where the unknown database table is transformed into a specific database table.

Note that there is no limit on the number of times which an abstract superclass can be inherited by a concrete subclass. In my own application I currently have over 450 database tables, so that is 450 cases of inheritance.

Procedural languages do not have inheritance. There is no way in which the code in one function can be merged with additional code to form another function. You can call another function, but you cannot share or modify its contents.

Polymorphism

Polymorphism Same interface, different implementation. The ability to substitute one class for another. This means that different classes may contain the same method signature, but the result which is returned by calling that method on a different object will be different as the code behind that method (the implementation) is different in each object.

More details can be found in Object-Oriented Programming for Heretics

To take advantage of polymorphism you must have code which calls one or more methods on an object, but where the identity of the object is not known. In this way you can reuse this code with a different object and it will produce different results. Here is an example of such code:

script: std.enquire1.inc
<?php
....
include "$table.class.inc";
$object = new $table;
$data = $object->getData($where);
....
?>

All that is required is a mechanism to supply the contents of $table. This can be done using a number of scripts constructed like the following:

script: foobar(enq1).php
<?php
$table = 'foobar'
include 'std.enquire.inc';
?>
script: snafu(enq1).php
<?php
$table = 'snafu'
include 'std.enquire.inc';
?>

As you should be able to see, if I have a separate one of these scripts for each database table, and I have 450 tables, it means that I can reuse the contents of std.enquire1.inc 450 times. This is possible because all my page controllers, of which std.enquire1.inc is just a small sample, use only those methods which were defined in the abstract class, which means that they can be used with anything which inherits from this class.

Procedural languages do not have polymorphism. Each function exists only once, therefore there cannot be more than one implementation with the same name, so it is not possible to swap one implementation with another.

Abstraction is not a separate concept

Some people seem to think that OO has four parts, with the fourth being "abstraction", but I disagree. For something to be an essential part of a programming paradigm then you MUST be able demonstrate its existence using code samples, but I have only seen such samples for the following:

  1. Encapsulation - uses the keyword "class" as a container (or capsule) for a series of related properties (variables) and methods (functions). A class can be instantiated into an object using the keyword "new" after which any of the methods in that object can be called.
  2. Inheritance - uses the keyword "extends" to automatically make available in a subclass all the properties and methods which were defined in the superclass.
  3. Polymorphism - allows the developer to define the same function name in several classes. This is not possible in procedural languages as each function/procedure name must be unique within the entire program.

Unless you can show me how to create this thing called "abstraction" using a code sample then, in my humble opinion, the whole idea can be disregarded as an illusion because it has no substance. The PHP manual does not have any keyword to perform an abstraction, so what exactly does it mean? After performing a search on the interweb thingy I found many descriptions, but nothing good enough to be called a "definition" which could explain the concept to a novice in simple and unambiguous terms. In a separate article called The meaning of "abstraction", which I wrote after discovering Designing Reusable Classes by Ralph E. Johnson & Brian Foote, I reveal how it is actually both a verb (process) and a noun (entity) which produces a result in two forms:

The process of abstraction means to separate the abstract from the concrete, the general from the specific. You examine a group of objects looking for both similarities and differences. The similarities can be shared by all members of that group while the differences are unique to individual members. The result of this process should then be an abstract superclass containing the shared characteristics and a separate concrete subclass to contain the differences for each unique instance.

If you look at a number of database tables you should note these similarities or common characteristics:

In order to turn an abstract class into a concrete class you need to provide the missing details:

The use of an abstract class means that it then becomes possible to make use of the Template Method Pattern to contain all common code in its invariant methods while the variable/customisable methods are defined separately in each subclass.

Note also that each table can contain any number of rows of data where each row has its own collection of values. While some columns may contain identical values each unique primary key will be unique. Each class should therefore contain properties for this data using one of the following choices:


They are the same except for ....

When people say that OO programming is completely different from procedural programming and it requires a totally different way of thinking I'm afraid that they are completely wrong. Yes, there are differences, but there are also similarities. The differences are not concerned with the code that you write to do stuff, but only how that code is packaged. With Procedural languages you can package your code into functions, procedures or subprograms, but with OO languages you can package your code into classes and methods. The use of classes then allows for inheritance where a subclass can share code from its superclass. In Procedural languages all function/procedure/subprogram names must be unique, whereas in OO languages the same method name may exist in multiple classes, thus providing opportunities for polymorphism. Inheritance and Polymorphism are techniques for reusing code that are not available in Procedural languages, and this simple observation leads me to make the following statement:

Object Oriented programming is exactly the same as Procedural programming except for the addition of encapsulation, inheritance and polymorphism. They are both designed around the idea of writing imperative statements which are executed in a linear fashion. The commands are the same, it is only the way they are packaged which is different. While both allow the developer to write modular instead of monolithic programs, OOP provides the opportunity to write better modules.

I am not the only one who shares this opinion. In his article All evidence points to OOP being bullshit John Barker says the following:

Procedural programming languages are designed around the idea of enumerating the steps required to complete a task. OOP languages are the same in that they are imperative - they are still essentially about giving the computer a sequence of commands to execute. What OOP introduces are abstractions that attempt to improve code sharing and security. In many ways it is still essentially procedural code.

In his paper Encapsulation as a First Principle of Object-Oriented Design (PDF) the author Scott L. Bain wrote the following:

Object Orientation (OO) addresses as its primary concern those things which influence the rate of success for the developer or team of developers: how easy is it to understand and implement a design, how extensible (and understandable) an existing code set is, how much pain one has to go through to find and fix a bug, add a new feature, change an existing feature, and so forth. Beyond simple "buzzword compliance", most end users and stakeholders are not concerned with whether or not a system is designed in an OO language or using good OO techniques. They are concerned with the end result of the process - it is the development team that enjoys the direct benefits that come from using OO.

This should not surprise us, since OO is routed in those best-practice principles that arose from the wise dons of procedural programming. The three pillars of "good code", namely strong cohesion, loose coupling and the elimination of redundancies, were not discovered by the inventors of OO, but were rather inherited by them (no pun intended).

Cohesion is the degree to which the responsibilities of a single module/component form a meaningful unit. High cohesion is considered to be better than low cohesion.

Coupling is the degree of interaction between two modules. Whenever you have one module calling another you have coupling. Loose coupling is considered to be better than tight coupling.

Elimination of redundancies is aimed at removing code that you do not need and is now called the YAGNI principle.

Other best practices which evolved in procedural languages, but which are still relevant in the OO world, are the KISS and DRY principles

Here is a summary of the similarities and differences:

This also tells me that OOP can be adequately supported in procedural languages (such as PHP and COBOL) which have had the necessary syntax added in to enable encapsulation, inheritance and polymorphism without replacing the original syntax with something which is more OO-like. For example, if a procedural language allows a statement such as $result = uppercase($string) it would seem to be overkill to replace it with $result = $string->uppercase(). The result is exactly the same, but a lot of effort has been expended just to do it differently.

OO theory is constantly being expanded to include more and more concepts, and these concepts are becoming more and more complicated. As languages are modified to include these add-on concepts newcomers to these languages become convinced that it is these add-ons which define what OO is. I totally disagree. OOP does not require the use of any of these optional extras, so it is wrong to say that a program is not OO simply because it does not use them. It would be like saying that a car is not a car unless it has climate control and satnav. Those are optional extras, not the distinguishing features, and not having them does not make your car not a car. It would also be incorrect to say that a car is a car because it has wheels. Having wheels does not make something a car - a pram has wheels, but that does not make it a car, so having wheels is not a distinguishing feature.


Not all OO code is good code

There seems to be a theory among OO programmers that all OO code is superior to procedural code by virtue of the fact that it is OO. In theory they should be correct, but in practice they are not. Just as it is possible to produce spaghetti code (unstructured branching using GOTO) in a procedural language it is also possible to produce ravioli code (too many small classes) or lasagne code (too many layers) in an OO language. Using the features that the language provides will not guarantee "good" code, it is how you make use of those features which is the deciding factor.

It is possible to write the same program in both a procedural style and an OO style, and for the results to be identical. If both have the same UI then it will not be possible for the user to identify which programming style was used. Does this make it an example of "implementation hiding"? This simple observation proves that the underlying code which "does stuff" is more or less the same, but it is only how this code is packaged which is different. When dealing with classes and objects there are four important questions to answer:

If you create too many objects, especially non-reusable objects, in a structure that is more complicated than it need be, then you may end up by actually being less productive than you could be. Your code may be more difficult to read and understand and therefore more difficult to maintain, which then totally negates the benefits of using OOP in the first place. If you cannot use the facilities that OO languages provide and create cost-effective software, and more importantly, software that is more cost effective than what can be produced using non-OO languages, then as far as I am concerned you have failed. Those OO features were added to languages in order to provide certain benefits, and if your work does not show those benefits then as far as I am concerned you are doing it wrong.


Conclusion

Anybody who says that OO programming is totally different from its procedural predecessors has been seriously misinformed. It is in fact exactly the same except for some minor differences. The code that you write to "do stuff" is fundamentally identical, with the only exception being how it is packaged. In procedural languages you wrap your code in plain functions, but with OO languages you wrap both code (methods) and data (properties) into capsules called classes. The act of encapsulation provides new ways of sharing and reusing code - inheritance and polymorphism. It is this ability to provide an increase in reusability and therefore maintainability which is supposed to give OOP the edge over its procedural predecessors, but too many programmers think that there is some sort of magic involved in OOP and invent weird sets of rules which, if not followed to their satisfaction, causes them to brand your code with what they regard as the ultimate insult - "That's not proper OO, that's procedural".

Do not think for one minute that you cannot possibly be wrong because you are following all the rules set by the programming elite. Far too many of these "rules" were created by pseudo-intellectuals whose purpose was to show how clever they are rather than providing simple solutions to complex problems. They spend so much time in nit-picking, pedantic arguments over their extreme and often perverse interpretations of various programming principles that they lose sight of the big picture. They concentrate too much on how the results should be achieved instead of what the results should be. If you don't belive me I suggest you take a look at the following:

As far as I am concerned the only difference between OO and procedural programming is that the former has encapsulation, inheritance and polymorphism while the latter does not. Remember that strong cohesion, loose coupling and the elimination of redundancies are concepts which are common to both paradigms. In order to be a competent OO programmer a person has to do no more than use the commonalities and leverage the differences to create cost-effective software which is easier to write and also easier to maintain. This is achieved by having more reusable code, and the correct application of inheritance and polymorphism can provide opportunities for code reuse which are simply not available in non-OO languages. The more code you have which is reusable the less code you have to write, and the less code you have to write then the less code you have to maintain. It is the result you obtain from using those concepts which is the deciding factor, not how you use them. It would be like saying that a footballer who puts the ball in the back of the net does not actually score a goal unless he kicks the ball properly, where "properly" means different things to different people. Just because a footballer kicks the ball "properly" does not guarantee that it will actually go into the back of the net, and a kick which does not score a goal cannot by any stretch of the imagination be classed as a success. It is substance that counts, not style. It is results that count, not rule-following.


References

The following articles describe aspects of my framework:

The following articles express my heretical views on the topic of OOP:

These are reasons why I consider some ideas to be complete rubbish:

Here are my views on changes to the PHP language and Backwards Compatibility:

The following are responses to criticisms of my methods:

Here are some miscellaneous articles:


Amendment History

01 Nov 2022 Amended Abstraction is not a separate concept
16 Apr 2022 Added Abstraction is not a separate concept

counter