Interfaces Without Inheritance: Comparing C++ and Common Lisp

Written by on April 24, 2025 in C++, LISP with 0 Comments

Clean interface design is a crucial aspect of software engineering since it enables code flexibility, reuse, and maintainability. Developers who prefer an object-oriented approach typically rely on inheritance to define the interface and thus establish type relationships. While this can lead to a good design if approached carefully, detractors of OOP point out that this can result in rigid hierarchies, and when multiple inheritance is used, it might lead to the infamous “diamond problem”.

Experienced C++ developers know that it is possible to define interface compatibility without necessarily resorting to inheritance. For example, “Concepts” introduced in C++20 offer an elegant, static, compile-time solution to this requirement. Common Lisp, being a dynamic language with support for advanced metaprogramming capabilities, allows us to model this use case differently. In this article, I would like to take a simple example, implement it using C++20 Concept and then show its corresponding (closest) Lisp implementation.

Take the example of two shapes, a Rectangle and a Circle. The common OOP approach uses inheritance, perhaps starting with an abstract base class called “Shape” and then publicly deriving Rectangle and Circle from it, and then overriding the appropriate methods. This typically involves dynamic binding.

Another approach, which is our focus today, uses C++20 “Concept” to model these classes but without using inheritance.

Rectangle and Circle Defined

Rectangle and Circle Defined

These classes are not derived from a common base class. Note also that I have defined the class “Locality” with the “area()” member function returning a “string” instead of a numeric value.

Let us now define our “Shape” Concept:

Shape Concept

Shape Concept

Thus “Shape” is a generic predicate that checks if the given type has an “area()” member function taking no parameter and returning a numeric value (that can be converted to a double). 

To show how this is used, I have defined a “printArea()” function that takes argument conforming to a “Shape” and then prints its area.

Here is the “main()” function:

Using the Concept

Using the Concept

When the last two lines are commented out, here is the program output:

Program Output

Program Output

If the last two lines are uncommented, the compiler generates error messages as expected:

Compiler Error

Compiler Error Message

The reason is obvious. These functions take arguments that do not satisfy the “Shape” constraint. Note carefully that even though “Locality” defines a member function called “area()”, it does not fully satisfy the constraint since it does not return a numeric value.

Let us now look at the Lisp implementation. As I said earlier, Lisp is different from C++ in that it is a dynamically typed language, so the checks are done at run time, not at compile time. We can issue directives to the compiler regarding types, optimization, safety, etc., but these are implementation dependent.

Here are the “rectangle” and “circle” classes:

Lisp Classes

Lisp Classes

Next we define methods for calculating “area” for different objects:

Defining Generic Methods

Defining Generic Methods

Note the default “area” method that returns zero. This method will normally be called when there is no other specific method that matches the call point.

Below we define the nearest equivalent of our C++ “Concept” definition. The “shape-p” method returns True if and only if there is a matching “area” method for the object passed as argument.

The Shape Constraint in Lisp

The Shape Constraint in Lisp

Next we define “print-area” function that prints the area of the given object. Note the “declaim” declaration before the method as a compiler directive. It states that the “print-area” function takes a “shape”- conforming object and returns anything. Also note the call to “check-type” in the method to forcibly check the type compatibility.

The print-area Method

The print-area Method

We then call “print-area” on a “rectangle” object as well as a “circle” object and these work fine because there is a corresponding “area” method. However, the last commented expression is illegal and it will trigger a runtime error.

Here is the actual output:

Lisp Program Output

Lisp Program Output

This example is an attempt to show that C++20 Concepts can be simulated in a dynamic language such as Lisp. It is not intended to compare languages otherwise.

The C++ program was tested in Visual Studio Professional (64 bit) ver 17.13.5. The Lisp program was tested in LispWorks Enterprise (64 bit) ver 8.0.1 as well as in Allegro CL Enterprise Edition (64 bit) ver 11.0.

You can download the C++ code and Lisp code.

Have a wonderful week!

Tags: , ,

About the Author

About the Author: .

Subscribe

If you enjoyed this article, subscribe now to receive more just like it.

Subscribe via RSS Feed

Leave a Reply

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

Top