Abstractions, a developers perspective

Abstract code is... art?
This might be slightly to abstract…

Last time, we talked about abstraction in more general terms. We discussed what abstractions are and how they are used in the real world. We saw what the concept was about and discussed the different kinds of abstractions that exist. This time, we are going to look at it from a developers perspective and how it materializes itself in code. I will be writing examples in C#, but they should all apply to most object-orientated programming languages.

Inheritance

Let’s start out with the most simple and basic concept, inheritance. Inheritance express the central concepts of generalization and specialization in code. When we say that B inherits A, it means that B inherits all non private members of A and that B and be used any where that takes A as a parameter. This is because B is just a more specialized version of A. It can do anything that A can do. This relationship can be written as follows:

public class Car
{
    public void Break() { ... }
    public void Accelerate() { ... } 
}

public class Convertible : Car
{
    public void TakeTopDown() { ... } 
}

Here, we say that the Convertible class inherits the Car class. We could ask the convertible to accelerate since it inherits all the members from the Car class. We could even assign it to a car type variable and send it in to a method that accepts a Car as a parameter.

void Refill(Car car) { ... } 

Convertible myConvertible = new Convertible();

//O.k, Convertible is a car
Refill(myConvertible); 
Car car = myConvertible; 

//Compile error, car is not a convertible. 
car.TakeTopDown();

//Compile error, can't downcast a car to a convertible. 
Convertible error = car;

With regards to the two last errors, even though the object itself is of a Convertible type, the variable is of type Car and we cannot treat it as a convertible. The last error is because it is not possible to explicitly perform a downcast. This follows from the fact that all convertibles are cars, but not all cars are convertibles. It is possible though to perform the downcast implicitly in C# using either typecasting or the “as/is” operators. This might cause runtime exceptions if the two types aren’t compatible, and I highly discourage doing so unless strictly needed.

Interfaces

Interfaces are the software equivalent of the “contracts” concept I mentioned in my previous article. They define behavior that any class that wants to implement that interface must fulfill. An interface and it’s implementation would look something like this:

public interface IDoctor
{
    string GetReference(List<Symptom> symptoms);
}

public class Surgeon : IDoctor
{
    public string GetReference(List<Symptom> symptoms) { ... }
    public void PerformSurgery(Patient patient) { ... }
}

The IDoctor interface only has one method that is required in order to successfully implement the interface and that is the GetReference method. We can now use them like this:

var surgeon = new Surgeon();

//Ok, no problem, he is a surgeon after all...
surgeon.PerformSurgery(somePoorFellow);

//No worries, surgeons are also doctors
IDoctor doc = surgeon;

//Valid, but shouldn't we be getting a reference BEFORE surgery? 
var reference = doc.GetReference(somePoorFellow.Symptoms);

//Compile error, doc is not a surgeon! (Uhhh.....)
doc.PerformSurgery(somePoorFellow);

//Error, can't downcast! 
Surgeon newSurgeon = doc;

Again, we have the same problems as before. Surgeon is always a doctor, but a doctor isn’t always a surgeon.

There are many other things that we can do with abstractions. Abstract classes are classes that cannot be instantiated and must be inherited in order to be used. Abstract methods on these classes force any class that inherits these types of classes to implement these methods. Virtual methods provide a default implementation that can be overridden by a specializing class. Polymorphism allows us to create methods that are specialized for different types in the same inheritance hierarchy. Sealing classes prevent them from being inherited by any other class.

I hope that this shed some light on how to use abstractions in your code and day to day. I also hope that this showed you how powerful when use in the right context.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.