Home | About | Partners | Contact Us
SourceForge Logo

Quick Links

Home
News
Thoughts and Rants
License
SourceForge Info
Download
Browse CVS
Mailing Lists

More about concepts

Concepts and Objects
Concepts in Lisp
Concepts and Intentions
Concepts and Patterns
Concepts and Aspects
Concepts and .NET
Concepts and UML
Terminology

Understanding...

Concept programming
Moka
XL
Thin Tools
Active Libraries
Refactoring
Optimizations
Coda
Notes

More Info

Contributors
Related Ideas
Some history
Applications
Other links
The GNU Project

Concept Programming vs. Objects

Object-oriented programming and design (OO) is a collection of well-respected and understood techniques to represent concepts as "objects". Simplifying slightly, OO maps "names" from the application domain onto "objects" in the code domain, and "verbs" in the application domain onto "methods" in the code domain. So for instance, to implement a graphical user interface, the programmer will create "Window" objects and "Draw" methods.

From that point of view, OO is a specific application of concept programming to the set of application concepts that can be represented as "names" or "verbs". Since this is a rather large set, OO itself applies to a large number of application domains.

The Maximum Concept

In order to illustrate how concept programming differs from OO, we can consider a concept that is not easily represented by a verb or a name, such as the mathematical concept of "maximum". That concept is fairly simple, but it doesn't map very well onto a name or a verb in the application domain.

Grammatically, "maximum" is a name all right, but one that doesn't generally denote an identifiable entity or class of entities in the application domain. This is more clearly visible if one tries to apply OO techniques too mechanically to the problem of computing the maximum in a set of values. The "name" in the application domain is "maximum", therefore there should be a "maximum" object. Similarly, there should be a "compute" method corresponding to the application domain verb. This yields code such as:

class Maximum {
	private int max;
	public void Compute(int data) { if (max < data) max = data; }
	public int Value() { return max; }
}

There is obviously something amiss in our design. For one, it is extremely cumbersome to use: you create a "maximum" object, and then accumulate values with "Compute", which incrementally computes the maximum, and finally "Value" will tell you the maximum value. This doesn't match the beautiful elegance of a mathematical notation such as "max(1,3,5,7)".

There are many other issues as well: the design only works for integers (and not on real numbers), the dependency of "maximum" on an order between integers is not explicit, there is a problem with the initial value, so we should probably add a "first" data member and a "Reset" method, nothing in the interface tells you that the maximum of nothing is not defined, and so on.

In short, the code doesn't represent the concept too well.

FAQ: But a real Java programmer would never write that! I hope so. The point of this code is not to show a good design, but rather how misapplication of object-oriented principles leads to bad design. Most programmers can avoid the problem on a trivial example like this, just by following their intuition. But the more complicated the concept, the more difficult it is to avoid the trap. This is where a method like concept programming becomes useful.

Alternative implementation

Maximum is an example of concept which is better represented by non-object code. For instance, a simple function with a limited number of arguments might be much easier to use in most cases:

int Max(int a, int b) { return a < b ? b : a; }

The code is shorter, simpler, and much easier to use. You can write Max(a, b), which is a very natural notation. For this particular concept, using an object-oriented design does not bring us anything, it simply adds noise. Other object-oriented representation of the Maximum concept are as likely to be more complicated than the simple Max function above. If your language forces you in the object-oriented world, like Java, then the simple function above has to be "methodified" (it has to be made a public static method of some class), which adds another tiny amount of noise. Little by little, the noise builds up.

How much of the code is "noise", as opposed to useful "signal", is an important metric of the quality of the code. For most concepts, the signal to noise ratio of the code can change dramatically depending on the representation being chosen. For many concepts, object-oriented design leads to code with a high signal-to-noise ratio, but occasionally, it's just the opposite.

Concept programming is one possible technique to identify when the signal-to-noise ratio of the code degrades, to understand why it degrades, and to help finding a more suitable representation. Concept programming is very agnostic with respect to objects: often they work, sometimes they don't. The concept programming approach doesn't care, it just tells you.

FAQ: But this doesn't work with 5 arguments, or with floating-point numbers! Indeed. This implementation has a high signal-to-noise ratio, but it has a narrow "bandwidth". In other words, it represents the concept closely, but only for a narrow region of the much larger space where the application concept applies. This is addressed below.

Maximum Requirements

In order to write code that represents the Maximum concept without irrelevant noise, and also for a large region of the application space where "Maximum" applies, we need more tools. The language being used is largely irrelevant to concept programming, but the tools that it gives you are not. When you don't have the right tools, you need to workaround, and working around leads to inferior code.

Maximum, for instance, applies to objects of various types. The way Java addresses the issue is with dynamic dispatch and polymorphism. If you spend a little time thinking about the problem, you might convince yourself that polymorphism (at least the Java flavor) doesn't apply well to this case. One reason is that what matters is the type of all arguments to Maximum, not just one. Polymorphism would introduce unnecessary semantic side effects or constraints. When the code representation doesn't behave as you would expect it from the concept, we can talk about concept mismatch. A concept mismatch introduces semantic noise in the code. There are other approaches to type variations, notably macros and generic (template) types. For the "Maximum" concept, generic types introduce the least noise. A language like Java, lacking generic types, forces you to workaround.

Maximum also applies to a variable number of arguments. Many languages don't have variable argument lists. Others, such as C and C++, have variable argument lists which are not type safe. Naturally, you can always workaround the problem by replacing the concept of the Maximum of N arguments with the concept of the Maximum of one argument which is a list with N elements. This is a particular form of workaround, called a concept cast, where you replace one concept which isn't representable easily in your language with a concept that suits the language better. Programmers often cast concepts implicitly, without even realizing it. But it is a bad thing, because it destroys the clear relationship between the concept and its representation in the code.

FAQ: Isn't that just syntactic sugar? When the absence of a given capability forces you to workaround it, add noise in your code, or make the code work incorrectly for a significant fraction of the expected domain space, then you can't talk about syntactic sugar. This has significant implications on programmer's productivity. Signal-to-noise degradation lowers the productivity at code implementation time. Bandwidth degradation lowers the productivity at code maintenance time.

Maximum in XL

The XL language incorporates the necessary elements to write a good representation of Maximum. The code below has a high signal-to-noise ratio (it doesn't contain much irrelevant code) and a high bandwidth (it covers a large spectrum of the concept in the application space). Other languages may have similar capabilities for that particular concept.

generic type ordered if
	with ordered A, B
	with boolean C := A < B

function Max(ordered N) return ordered is
	return N

function Max(ordered N; other) return ordered is
	result := Max(other)
	if result < N then
		result := N

with real R := Max(1.7, 2.5, 3.9, 8.2)
with integer N := Max(1, 3, 5, 2, -1)

Signal-to-noise: If you put the XL code side by side with a definition of Maximum as a mathematician would write it, there is not much syntactic or semantic information in the XL code which is irrelevant. There is some noise left: the name C, the fact that you can assign to a boolean (as opposed to "it is a boolean"), and argument passing / value return semantics (for instance, you might "run out of stack space" by calling this Max function).

Bandwidth: The concept above works directly for any type which has a < operator. Since XL lets you define and overload operators easily, this code covers a lot of the application space. For text, it would be possible to define the < operator in a few different ways depending on the locale and character representation. However, there are still cases that are important for the mathematician or programmer, but not covered correctly by this implementation (at least not without additional code). For instance, if you take the "maximum of an array", you probably expect the largest element of that array, not the array itself.

Conclusion: by consciously not using an OO approach, we can now represent something that is much closer to the original application concept. The dependency of Max on an order between elements is explicit (as defined by the ordered type). The implemented Max function can be used with data of any ordered type, and for any non-zero number of arguments. There is no artificial complexity like a class, a "private member", problems with the initial conditions, or other implementation difficulties that resulted from a bad initial design choice. But remember: The XL implementation is still only a representation of the concept, not the concept itself!

FAQ: Are you trying to start a language war between Java and XL? In its current state, that's a war that XL would certainly lose, because it still lacks much more essential features. By the time XL has garbage collection, a decent class library, serialization and database access, Java might have variable argument lists and generics... The point of this exercise is rather to show how concept programming is not object-oriented design, but rather something that helps you qualify and quantify OO benefits (or lack thereof) depending on the context.

Should I avoid objects, then?

Of course, you should not avoid objects. In many cases, objects are one of the most natural representations in code of the application concept. But objects are not a panacea either. Use objects where they make sense (often), use something else where they don't. And then, you will be applying the key rule of concept programming: Your code should represent the application concepts.


Copyright Christophe de Dinechin
First published Feb 17, 2000
Version 1.4 (updated 2002/12/07 16:32:57)