I feel obligated to part of myself to type up some notes from my "exploratory investigations." Some of these notes are from a 1200 page text book mixed with other sources. I feel a need to articulate what I find so interesting about "generic programming."
----------------------------------------------------------------------------------------------
First of all, may I suggest
From Mathematics to Generic Programming" by Alex Stepanov and Daniel Rose, a book I mentioned in the "Generic Programming" thread:
http://whybother.freeboards.org/math-diary/generic-programming/ (very related to this thread).
-------------------------------------------------------------------------------------------
My apologies for putting on my "technician's hat." Just remember that the creature who types is still this frustrated, albeit philosophical, animal with forever-growling stomach, rotten teeth, bad breath, and excrement quite nasty!
----------------------------------------------------------------------------------------
From a 2006 paper by Peter Gottschling, "
Fundamental Algebraic Concepts in Concept-Enabled C++":
symbiosis -
the relation between two different species, where each gains benefits from the other.
Using generic programming concepts to define algebraic structures is an organic symbiosis between generic programming and abstract algebra. At first, the idea of concepts was adapted from algebra to generic programming. Now, algebraic structures are specified with the generic programming concepts.
-------------------------------------------------------------------------------------------
In Bjarne Stroustrup's textbook, Programming: Principles and Practice Using C++, early on in chapter 20, he writes, "We look at the STL [Standard Template Library] not just as a useful set of facilities, but also as an example of a library designed for maximal flexibility and performance. The STL was desgined by Alex Stepanov to provide a framework for general, correct, and efficient algorithms operating on data structures.
The ideal was the simplicity, generality, and elegance of mathematics.
From page 681, chapter 19:GENERIC PROGRAMMINGTemplates are the basis for generic programming in C++. In fact, the simplest definition of “generic programming” in C++ is “using templates.” That definition is a bit too simpleminded, though. We should not define fundamental programming concepts in terms of programming language features. Programming language features exist to support programming techniques — not the other way around. As with most popular notions, there are many definitions of "generic programming.” We think that the most useful simple definition is
Generic programming: Writing code that works with a variety of types presented as arguments, as long as those argument types meet specific syntactic and semantic requirements.
When what we parameterize is a class, we get a class template, what is often called a parameterized type or a parameterized class. When what we parameterize is a function, we get a function template, what is often called a parameterized function and sometimes also called an algorithm. Thus, generic programming is sometimes referred to as “algorithm-oriented programming”; the focus of the design is more the algorithms than the data types they use.
Since the notion of parameterized types is so central to programming, let’s explore the somewhat bewildering terminology a bit further. That way we have a chance of not getting too confused when we meet such notions in other contexts. This form of generic programming relying on explicit template parameters is often called parametric polymorphism. In contrast, the polymorphism you get from using class hierarchies and virtual functions is called ad hoc polymorphism and that style of programming is called object-oriented programming.
The reason that both styles of programming are called polymorphism is that each style relies on the programmer to present many versions of a concept by a single interface. Polymorphism is Greek for “many shapes,” referring to the many different types you can manipulate through a common interface.
There are several differences between object-oriented programming (using class hierarchies and virtual functions) and generic programming (using templates). The most obvious is that the choice of function invoked when you use generic programming is determined by the compiler at compile time, whereas for object-oriented programming, it is not determined until run time.
So — assuming you have had your fill of philosophy for now — what do people actually use templates for?
For unsurpassed flexibility and performance:
• Use templates where performance is essential (e.g., numerics and hard real time)
• Use templates where flexibility in combining information from several
types is essential.
C O N C E P T SAs usual, the benefits have corresponding weaknesses. For templates, the main problem is that the flexibility and performance come at the cost of poor separation between the “inside” of a template (its definition) and its interface (its declaration). This manifests itself in poor error diagnostics — often spectacularly poor error messages. Sometimes, these error messages come much later in the compilation process than we would prefer.
When compiling a use of a template, the compiler “looks into” the template and also into the template arguments. It does so to get the information to generate optimal code. To have all that information available, current compilers tend to require that a template must be fully defined wherever it is used. That includes all of its member functions and all template functions called from those. Consequently, template writers tend to place template definitions in header files. This is not actually required by the standard, but until radically improved implementations are widely available, we recommend that you do so for your own templates: place the definition of any template that is to be used in more than one translation unit in a header file.
(This means you don't have a separate .h and .cpp file for declarations and definitions, respectively; but define everything in one .h file.)
C++14 provides a mechanism for vastly improved checking of template interfaces. For example, in C++11, we write:
template<typename T> // for all types T
class My_Vector {
// ...
};
We cannot precisely state what is expected of an argument type T. The standard says what these requirements are, but only in English, rather than in code that the compiler can understand. We call a set of requirements on a template argument a
concept.
A template argument must meet the requirements, the concepts, of the template to which it is applied. For example, a vector requires that its elements can be copied or moved, can have their address taken, and be default constructed (if needed). In other words, an element must meet a set of requirements, which we could call Element.
In C++14, we can make that explicit:
template<typename T> // for all types T
requires Element<T>() // such that T is an Element
class vector {
// . . .
};
This shows that a concept is really a type predicate, that is, a compile-time-evaluated (constexpr) function that returns true if the type argument (here, T) has the properties required by the concept (here, Element) and false if it does not.
This is a bit long-winded, but a shorthand notation brings us to
template<Element T> // for all types T, such that Element<T>() is true
class vector {
// . . .
};
The compiler doesn’t understand our names or read our comments, but being
explicit about concepts helps us think about our code, improves our design of
generic code, and helps other programmers understand our code. As we go along,
we will use some common and useful concepts:
• Element<E>(): E can be an element in a container.
• Container<C>(): C can hold Elements and be accessed as a [begin():end())
sequence.
• Forward_iterator<For>(): For can be used to traverse a sequence [b:e)
(like a linked list, a vector, or an array).
• Input_iterator<In>(): In can be used to read a sequence [b:e) once only
(like an input stream).
• Output_iterator<Out>(): A sequence can be output using Out.
• Random_access_iterator<Ran>(): Ran can be used to read and write a
sequence [b:e) repeatedly and supports subscripting using [ ].
• Allocator<A>(): A can be used to acquire and release memory (like the
free store).
• Equal_comparable<T>(): We can compare two Ts for equality using == to
get a Boolean result.
• Equal_comparable<T,U>(): We can compare a T to a U for equality using
== to get a Boolean result.
• Predicate<P,T>(): We can call P with an argument of type T to get a Boolean result.
• Binary_predicate<P,T>(): We can call P with two arguments of type T to
get a Boolean result.
• Binary_predicate<P,T,U>(): We can call P with arguments of types T and
U to get a Boolean result.
• Less_comparable<L,T>(): We can use L to compare two Ts for less than
using < to get a Boolean result.
• Less_comparable<L,T,U>(): We can use L to compare a T to a U for less
than using < to get a Boolean result.
• Binary_operation<B,T,U>(): We can use B to do an operation on two Ts.
• Binary_operation<B,T,U>(): We can use B to do an operation on a T and a U.
• Number<N>(): N behaves like a number, supporting +, -, *, and /.
_____________________________________________________________________
This is a more philosophical treatment of a technical subject than is usually available, so I thought it worthy to be stored here on our "old school message board" for posterity (or just to continue to daydream of ways to bring together my interests in abstract algebra and computing ...
When my stomache growls, I catch myself wishing I were dead and no longer needed to eat food and shiit. Not much interests me in this world ... and I foresee myself spending the remainder of my days on earth sulking and brooding, with some moments of delight upon grasping such abstractions.
I apologize again for such technical posts. I am still quite philosophical, but the thoughts I have been "entertaining" have been too dark to verbalize. Perhaps my heart is finally going bad. I mean, I don't want to feel so much distress and anguish. I don't want to make this life any harder than it actually is.
I thank each of you for your philosophical and often poetic prose.
Being a human animal, well, as each of you know, has a very tragic element to it.