DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
The Latest "Software Integration: The Intersection of APIs, Microservices, and Cloud-Based Systems" Trend Report
Get the report
  1. DZone
  2. Coding
  3. Frameworks
  4. The Secret Life of Objects: Information Hiding

The Secret Life of Objects: Information Hiding

This article looks at object-oriented programming and the complexity surrounding objects by looking at specific examples and types of information hiding.

Riccardo Cardin user avatar by
Riccardo Cardin
·
Jun. 21, 18 · Tutorial
Like (8)
Save
Tweet
Share
10.26K Views

Join the DZone community and get the full member experience.

Join For Free

I’ve been in the software development world for a while, and if I understand a single thing, it is that programming is not a simple affair. Along with that, object-oriented programming is even less accessible. The idea that I had of what an object is after I finished college is very far from the idea I have of it now. Last week, I came across the blog post Goodbye, Object Oriented Programming. After reading it, I realized how easily object-oriented programming can be misunderstood. I am not saying that I have the last answer to the million dollar question, but I will try to give a different perspective and my personal understanding of object-oriented programming.

Introduction

This will probably be the hardest post I have ever written. It is not easy to explain the basis of object-oriented programming. I think that the first thing we need to do is to define what an object is.

Below, I provided a definition of objects:

The aim of object-oriented #programming is not modeling reality using abstract representations of its component, accidentally called "objects". #OOP aims to organize behaviors and data together in structures, minimizing any dependencies among them.

Image title

Messages Are the Core

In the beginning, there was procedural programming. Exponents of such programming paradigms are languages like COBOL, C, PASCAL, and, more recently, Go. In procedural programming, the building blocks are represented by the procedure, which is a function (not mathematically speaking) that takes some input arguments and could return some output values. During its evaluation, a procedure can also have side effects.

Data can have some primitive forms, like int or double, or it can be structured into records. A record is a set of correlated data, like a Rectangle, which contains two primitive height and length of type double. Using C notation, the definition of a rectangle is the following:

struct Rectangle {
   double   height;
   double   length;
};


Despite inputs and outputs, there is no direct link between data (records) and behaviors (procedures). So, if we want to model all the operations available for a Rectangle, we have to create many procedures that take it as an input.

double area(Rectangle r)
{
    // Code that computes the area of a rectangle 
}
void scale(Rectangle r, double factor)
{
    // Code that changes the rectangle r, mutating its components directly
}


As you can see, every procedure insists on the same type of structure: the Rectangle. Every procedure needs an input and an instance of the structure on which it executes. Moreover, every piece of code that owns an instance of the Rectangle structure can access its member values without control. There is no concept of restriction or authorization.

The above fact makes the procedures’ definition verbose and maintenance can be very tricky. Tests become very hard to design and execute, because of the lack of information hiding — everything can modify everything.

The primary goal of object-oriented programming is that of binding the behavior (i.e. methods) with the data on which they operate (i.e. attributes). As Alan Kay once said: "[..] it is not even about classes. I’m sorry that I long ago coined the term “objects” for this topic because it gets many people to focus on the lesser idea. The big idea is “messaging.”

The concept of classes allows us to regain the focus on behavior and not on methods inputs. You should not even know the internal representation of a class. You only need its interface. In object-oriented programming, the example below becomes the following class definition. I chose Scala for this example because of its lack of ceremony.

trait Shape {
    def area: Double
    def scale(factor: Double): Shape
}
case class Rectangle(height: Double, length: Double) extends Shape {
    // Definition of functions declared abstract in Shape trait
}


The example given is very trivial. Starting from elements height, length, and procedures scaleand area, it was very straight to derive an elegant object-oriented solution. However, is it possible to formalize (and, maybe to automate) the process we just did to define the class Rectangle? Next, I will try to answer this question.

Information Hiding and Class Definition

We can begin with an unstructured set of procedures:

def scale(height: Double, length: Double, factor: Double): (Double, Double) = {
    (height \* factor, length \* factor)
}
def area(height: Double, length: Double): Double = {
    height * length
}


First of all, we notice that height and length parameters are present in both procedures. We might create a type for each parameter, like Height and Length. However, we immediately understand that the two parameters are always used together in our use cases. There are no procedures that use only one of the two.

So, we decided to create a structure to bind them together. We call this structure Rectangle.

type Rectangle = (Double, Double)


We also understand that a simple structure does not fit our needs. Rectangle internal should not be changed by anything else other than the two procedures (forget for a moment that tuples are immutable in Scala). Here, we are only interested in the two procedures. So, we restrict the access to rectangle information only to the two procedures.

How can we do that? We should bind information of a rectangle with the behaviors associated with it. We need a class.

case class Rectangle(height: Double, length: Double) {
    def scale(factor: Double): Rectangle = Rectangle(height * factor, length)
    val area: Double = height * length
}


Well, taking into consideration the only use cases we have, we could stop here. The solution is already optimal. We hid the information of height and length behind our class; the behavior is the only thing client can access from the outside. However, clients that want to use a rectangle can interact only with the interface of the class Rectangle.

What if we want to support shapes like squares and circles? Well, through the use of interfaces, which are types with pure behavior, object-oriented programming allows our clients to grow more abstract from the concrete implementation of a shape. Next, the above example becomes the following:

trait Shape {
    def scale(factor: Double): Shape
    def area: Double
}
case class Rectangle(height: Double, length: Double) extends Shape {
    // Definition of functions declared abstract in Shape trait
}
case class Square(length: Double) extends Shape {
    // Definition of functions declared abstract in Shape trait
}
case class Circle(ray: Double) extends Shape {
    // Definition of functions declared abstract in Shape trait
}


As Wikipedia reminds us, "Information hiding is the principle of segregation of the design decisions in a computer program that is most likely to change, thus protecting other parts of the program from extensive modification if the design decision is changed. The protection involves providing a stable interface which protects the remainder of the program from the implementation (the details that are most likely to change)."

Information Hiding and Dependency Degree

As anyone who has followed me for some time already knows, I am a big fan of dependency degree minimization between classes. I have developed a small theoretical framework that allows for calculating the dependency degree of the architecture. This framework is based on the number of dependencies a class has with other classes and the scope of these dependencies, concerning a class life cycle.

I have already used my framework in other circumstances, like when I spoke about the Single-Responsibility Principle. This time, I will try to use it to sketch the process we just analyzed. The goal of this is to aggregate information and related behaviors inside the same class, hiding the former to the clients of the class. I will try to answer the question: why are height and length collapsed inside one single type (which is incidentally called Rectangle)?

Just as a recap, I defined in the post Dependency the degree of dependency between classes A and B as:

Image title

φSA|B is the quantity of code (i.e. SLOC) that is shared between types A and B. φStotB is the total number of code (i.e. SLOC) of the B class. Finally, εA→B is a factor between 0 and 1. And, the wider the scope between A and B , the greater the factor.

If Height and Length had each been defined as dedicated types, then the client C that needed to use a rectangle would always have to use both types. Moreover, the Rectangle type would still have been necessary to put the methods area and scale. Using this configuration, Rectangle, Height, and Length are said to be tightly coupled, because they are always used together.

The degree of dependency of class C would be very high, using the above definition. Also, the degree of dependency of class Rectangle would be high, due to references to Height and Length in the methods area and scale.

It is likely that many class configurations can reduce the degree of dependency of the above example. However, the minimization of the value δtotC can be reached by the solution we gave in the previous paragraph.

In some ways, we started to trace a new way of design architecture, reducing the art of desig to find an architecture that minimizes a mathematical function on the degree of dependency. Nice!.

Conclusion

To sum this all up using a toy example, we tried to sketch the informal process that should be used for defined types and classes. We started from the lacks we find in procedural programming paradigm, and we ended up trying to create a mathematical formulation of this process. All the ideas we used are tightly related to the basic concept of information hiding that we confirmed to be one of the most essential concepts in object-oriented programming.

This post is just my opinion. It was not my intention to belittle procedural programming but to celebrate object-oriented programming.

Information hiding Object (computer science) Object-oriented programming Dependency

Published at DZone with permission of Riccardo Cardin, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Key Elements of Site Reliability Engineering (SRE)
  • Use AWS Controllers for Kubernetes To Deploy a Serverless Data Processing Solution With SQS, Lambda, and DynamoDB
  • 7 Ways for Better Collaboration Among Your Testers and Developers
  • Integrating AWS Secrets Manager With Spring Boot

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: