What is an Abstraction?

An abstraction as a term has many meanings. Reading a lot of computer science textbooks, tech documentation, I have bumped into the word quite a few times, and it has always been ambiguous what that refers to exactly. You can hear terms such as “abstract data types”, “functional abstraction”, “abstraction in OOP” (although a few people have claimed that it is confusing too), but it might not be clear how exactly they are “abstract”.
A fairly good blogposts already existing on the platform are “What is “Abstraction” in Programming?” by Brandon Burrus and “Abstraction & Composition” by Eric Elliott , so I clearly do recognise the attempt to describe the term is not new, however, it is my own approach to describe it.
On how many levels of abstraction are you?
Abstraction is theory. A theory is a principle that attempts to explain diverse phenomena, a concise concept capable of shedding light on countless situations.
In the analogue/physical world an abstraction is something invisible, something “hidden” from us, such as how a coffee machine works (we only need to press the button, we don`t care about the electronics). We can say that the coffee machine is an abstraction, we communicate with it through an API, aka. button on a screen.
The truth is, a lot of things can be called an abstraction. An API endpoint is an abstraction, a function is an abstraction, a variable declaration, yes, also an abstraction.
It is so broadly used, that I felt dumb not really getting the idea until a read a great book called “An Introduction to Functional Programming Through Lambda Calculus” by Greg Michaelson. I got a better understanding of what an abstraction denotes as I stared learning functional programming.
This blogpost will be using a lot of examples from the book, but I really advise you to read it.
Breaking down a simple abstraction
Abstraction is the crucial approach to writing software. Abstraction involves generalisation from concrete instance of a problem so that a general solution may be formed. A general, abstract solution may then be used in turn to solve particular, concrete instances of the problem.
Abstraction is based on the use of names to stand for concrete objects and operations, to generalise the instances. — by Greg Michaelson.
I will use a somewhat simplistic example, but you will soon get my point. Consider buying 9 items at 10 euros each at a store. The total cost is calculated like so:
10*9
Here we are performing the concrete operation of multiplication on the concrete values of 10 and 9. Now consider buying 11 items at 10 euros each.
10*11
Here we are performing the concrete operation of multiplication on the concrete values of 10 and 11.
We can see that as the numbers of items changes and as the result the formula for the total cost changes at the same place where the number of items appears. We can abstract over the number of items in the formula by introducing a name to stand for a general number of items, say ‘items’:
10*items
We might make this abstraction explicit by preceding the formula with the name used for abstraction:
REPLACE items IN 10*items
and thus we have abstracted over an operand in the formula.
To evaluate this abstraction, we need to supply a value for the name. For example, with 84 items:
REPLACE items WITH 84 IN items*10
which gives
10*84
We have made a function for a formula by replacing an object with a name and identifying the name that we used. We have then evaluated the function by replacing the name in the formula with a new object and evaluating the resulting formula. “Items” is the abstraction.
We can use abstraction again to generalise the example further. Suppose the cost of the items go up to 11 euros or drops to 8 euros.
REPLACE items IN 11*items
and
REPLACE items IN 8*items
Because we know that the cost changes, we can introduce a name to stand for the price in general, say cost:
REPLACE cost IN
REPLACE items IN cost*items
Here we have abstracted over two operands in the formula. To evaluate it, we need to supply two values:
REPLACE cost WITH 32 IN
REPLACE items WITH 12 IN cost*items
which is
REPLACE items WITH 12 IN 32*items
which is
32 * 12
We could do the same for any combination of costs and number of items.
Higher level of abstraction
Now, suppose we want to solve a different problem: we are given the total cost and the number of items and we are supposed to find out how much each of these item cost? Suppose 144 is the price and we have 12 items.
REPLACE cost IN
REPLACE items IN cost/items
How does it compare to the previous formula?
REPLACE cost IN
REPLACE items IN cost*items
They are the same except for the operation /, so we could generalise it even further:
REPLACE op IN
REPLACE cost IN
REPLACE items IN cost op items
and depending on the operation, we can either find the total cost of the items or a cost of one item knowing the total cost
REPLACE op WITH * IN
REPLACE cost IN
REPLACE items IN cost op items
or
REPLACE op WITH / IN
REPLACE cost WITH 32 IN
REPLACE items WITH 12 IN cost op items
Abstraction is based on generalisation through the introduction of a name to replace a value and specialization through the replacement of a name with another value. — by Greg Michaelson.
Wait, didn’t we just introduced a variable instead of a hard-coded value? Well, yes. That variable is an abstraction. We replaced a concrete instance of a number with an equivalent generalised name, and that is exactly what abstraction is. With the same logic we can say that named functions are abstractions, even API endpoints are abstraction.
I think of abstractions as named collections of operations. If you can perform all of an abstraction’s operations on an object, then that object is an instance of the abstraction. I think this way even outside of programming. For example, the battery abstraction includes the operation “connect a conducting medium to its anode and cathode,” and the operation’s output is electrical current. It doesn’t matter if the battery is made out of lithium or out of potatoes. It’s a battery as long as it responds to the set of operations that define battery. — from Clojure for the Brave
An abstraction can be an incredibly powerful tool in software design. Microservices design is built on top of this idea. State management is built on top of it.
I do recommend you to check the books below to learn more!