9

Also on stackoverflow.com:

I understand that STL concepts had to exist, and that it would be silly to call them "classes" or "interfaces" when in fact they're only documented (human) concepts and couldn't be translated into C++ code at the time, but when given the opportunity to extend the language to accomodate concepts, why didn't they simply modify the capabilities of classes and/or introduced interfaces?

Isn't a concept very similar to an interface (100% abstract class with no data)? By looking at it, it seems to me interfaces only lack support for axioms, but maybe axioms could be introduced into C++'s interfaces (considering an hypothetical adoption of interfaces in C++ to take over concepts), couldn't them? I think even auto concepts could easily be added to such a C++ interface (auto interface LessThanComparable, anyone?).

Isn't a concept_map very similar to the Adapter pattern? If all the methods are inline, the adapter essentially doesn't exist beyond compile time; the compiler simply replaces calls to the interface with the inlined versions, calling the target object directly during runtime.

I've heard of something called Static Object-Oriented Programming, which essentially means effectively reusing the concepts of object-orientation in generic programming, thus permitting usage of most of OOP's power without incurring execution overhead. Why wasn't this idea further considered?

I hope this is clear enough. I can rewrite this if you think I was not; just let me know.

4 Answers 4

13

Short answer : You're mixing before-compile-time and compile-time concepts that have similarities in their purpose. Interfaces (abstract classes and all the object-orientation paradigm implementation) are inforced at compile-time. Concepts are the same idea but in the context of generic programming that in C++ occurs BEFORE compile time. We don't have that last feature yet.

But let me explain from the beginning.


Long answer:

In fact, Concepts are just language inforcement and "made easier for the programmer" of something already present in the language, that you could call "duck typing".

When you pass a type to a template function, that is a generic function from which the compiler will generate real (inline) code when called, that type needs to have some properties (traits?) that will be used in the template code. So it's the idea of duck-typing BUT it's all generated and done at compile time.

What happens when the type don't have the required properties?

Well, the compiler will know that there is a problem only once the generated code from the template is compiled and fail. That means that the error that will be generated will be an error inside the template code, that will be shown to the programmer as his error. Also, the error will have tons of informations because of the meta informations provided in case of template code generation, to know which instantiation of the template we're talking about.

Several problems with that : first, most of the time, template code is library code and most programmers are users of library code, not writers of library code. That means that this kind of cryptic error is really hard to understand when you don't understand how the library is written (not just the design, how it is really implemented). The second problem is that even when the programmer did write the template code, the reasons of failure might still be obscure because the compiler will be able to tell that there is a problem too late : when the generated code is being compiled. If the problem is relative to the type properties, then it should check it even before generating the code.

That's what Concepts allow (and are designed for) : to allow the (generic code) programmer to specify the properties of types being passed as template parameters and then to allow the compiler to provide explicit errors in case the provided types don't fulfill the requirements.

Once the check is successful, the code will be generated from the template and then compiled, certainly successfully.

All the Concept checking occurs exclusively before compile-time. It checks types themselves, not object's types. There is no object before compile-time.

Now, about "interfaces".

When you create an abstract or virtual base type, you're allowing code using it to manipulate objects of the child types without knowing their real implementations. To enforce this, the base type expose members that are virtual and might be (or have to be) overloaded by the child types.

That means that the compiler can check at compile time that all objects passed to a function requiring a reference to the base class have to 1. be of one of the child types of the base class, 2. that child type have to have implementations of virtual pure functions declared in base classes if any.

So at compile-time, the compiler will check the interfaces of object's types and report if something is missing.

It's the same idea than Concepts, but it occurs too late, as said in the Concept description. It occurs at compile-time. We're not in generic code (template code), we're after it have been processed and it's already too late to check if the types fulfill generic requirements, that cannot be exposed by virtual base classes. In fact, the whole object orientation paradigm implementation in C++ don't even exists when the template code is being processed. There is no objects (yet). That's

Classes describe constraints on objects to be used to check requirements for functions manipulating those objects. Concepts describe constraints on types (including classes) to be used to check requirements for generic code to generate real code from those types and generic code combination.

So, again, it's the same "sanity check", but in another layer of the language, that is templates. Templates are a full (turing complete) language that allow meta-programming, programming types even before they appear in the compiled code. It's a bit like scripting the compiler. Let's say you can script it, classes are just values manipulated by the script. Currently, there is no way to check constraints on these values other than to crash the script in a non-obvious way. Concepts are just that : provide typing on these values (that in generated code are types). Not sure I'm clear...

Another really important difference between virtual base classes and Concepts is that the first one forces a strong relation between types, making them "bound by blood". While template metaprogramming allow "duck typing" that Concepts just allow to make requirements clearer.

4

Declaring a class is "programming objects".
Declaring a concept is "programming classes".

Of course, since always programming is, certain analogies can be seen, but the two things belong to a different phase of the abstraction process. Basically a "class" (and everything is around it, like "interfaces") tells the compiler how to structure the objects that the executor machine will instantiate at runtime. A "concept" is meant to tell the compiler how a "class" should be structured to be "compilable" in a given context.

Of course, it is theoretically possible to reiterate these steps over and over having

  • objects
  • types of objects (classes)
  • types of (types of objects) (concepts)
  • types of (types of (types of objects)) ( ??? )
  • .....

Right now, "concepts" have been dropped by the C++0x specifications (since they still require some work, and was retained was not the case to delay anymore) The idea of conceptn I don't know -right now- if can be ever useful.

1
  • That makes a lot of sense conceptually; I'm trying to sink it in and think if this answers the question. Thanks a lot.
    – Gui Prá
    Sep 2, 2011 at 7:17
4

The simple answer to virtually all of your question is, "Because C++ compilers suck". Seriously. They're built on C's Translation Unit technology, which effectively bans many useful things, and the existing template implementations are hideously slow as they are. Concepts weren't cut for any conceptual reason- they were cut because there was no reliable implementation, ConceptGCC was extremely slow, and specifying concepts took an absurdly long time. Herb Sutter stated that it took more space to specify the concepts used in the Standard library than to specify the entire of templates.

Arguably, between SFINAE, decltype and static_assert, they're mostly implementable as it is now anyway.

2

In my understanding, Interfaces and Concepts have similar purposes in different parts of the C++ language.

As mentioned in the reply to the original question: The implementation of an Interface is decided by the implementor of a class at design time. Once a class has been published it can support only those interfaces it was derived from at design time.

Two distinct Interfaces with exactly the same member functions and semantics (i.e. the same concept) will still be two distinct Interfaces. If you wish to support the semantics of both Interfaces you may have to implement support twice.

That's the issue that Generic Programming intends to work around. In C++ Generic Programming the type passed to a template simply needs to support the interface (non-capitalized, in the sense of the "programming interface" of a type) that is used by the template. The two distinct Interfaces with the same member functions will match, and you will need to write the code only once. In addition, any types (even without explicit Interfaces) that support the same interface will work with.

This leads to a second issue: what if you have two types with overlapping interfaces but different semantics? Generic programming will not be able to tell the difference and everything will compile just fine, but the run-time result will be suprising and probably wrong.

That's where Concepts come in. If you grossly oversimplify you can consider a Concept the generic (template) version of an Interface. It needs to be implemented only once to apply to a large number of potential types that can "derive" from the Concept. A Concept is a predetermined semantic interface of a (class-)type that is not limited to that type only. It is unlike an Interface in that two very different types (to the generic compiler) can still have the same Concept, without having to resort to limiting base-class Interfaces, or base-class Interfaces that have no actual compiler-visible semantics of their own but are only used for type distinction.

2
  • Hold on... You said concepts are implemented once and apply to a large number of potential types that can "derive" from it. That means all potential types have to derive from it. If two concepts with the same contents are present in two different libraries, without automatic mapping, you've got the same problem as Interfaces. At the same time, an Interface could well feature automatic mapping. The problems look one and the same to me.
    – Gui Prá
    Sep 2, 2011 at 7:30
  • 1
    @n2liquid - Concepts are a different mix of benefits and drawbacks between Interfaces and pure Generic Programming. They are not a strict improvement. Concepts do not avoid the "predetermined" part of Interfaces. Concepts DO avoid the situation where class types support the same semantics but can't derive from the same Interface (e.g. where the interface is defined for subtype double, while the generic version applies to all numeric types). Sep 2, 2011 at 7:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.