Are C++ concepts a form of existential type? - c++

I was looking at the definition of existential types on Wikipedia (Existential_types) and it feels similar in some way to concepts in C++ (particularly to concepts lite).
Are C++ concepts a form of existential type?
If not, what are the differences between the two?

TL;DR: Yes, Concepts are (or at least allow you to define) existential types.
Here's my reasoning, though be warned; I'm not a type theorist:
Consider Wikipedia's definition of abstract data type (emphasis mine):
In computer science, an abstract data type (ADT) is a mathematical model for a certain class of data types of one or more programming languages that have similar semantics. An abstract data type is defined indirectly, only by the operations that may be performed on it and by mathematical constraints on the effects (and possibly cost) of those operations.
Existential types, as described by these two Stack Overflow questions and the Wikipedia article you linked, seem to be a way of modelling abstract data types using parameterized definitions. Importantly, those parameters are not part of the resulting existential type.
At face value, a concept on the other hand is a predicate on one (zero?) or more types, which can be used to restrict templates. It's not obvious that they bear any relation to existential types— until you consider requires clauses.
Basically, requires allows you to test for certain properties of types. Among these are whether they define a certain member type, have a certain member function, are convertible to certain types, etc. This observation (the main point of design, really) is where the meat of the matter lies.
It seems to me, at least, that what concepts fundamentally are is a mechanism for defining abstract data types. This is where we begin to see the similarity to existential types: they model ADTs by parameterization, and more importantly, allow you to define the ADT without exposing the parameters.
Take the Container concept, for example. You may, with Concepts Lite, write something like
void print (Container c) {
for (const auto& e : c)
print (e);
}
// Later
print (std::vector <int> {1, 2, 3, 4});
This works because there exists some type I such that the expressions begin (c) and end (c) return objects of type I, along with Container's other constraints. That's existential quantification; Container is an existential type.

As far as I know, C++ concepts are arbitrary type predicates. The work on C++ concepts concentrates more on how these predicates integrate into the language rather than on giving a particular meaning or specifying a mathematical / logical model. The idea is that exactly as a function
void f(double x);
is clearly expecting a parameter of type double, in such a simple way
template <Container C>
void f(const C& c);
is expecting not just a typename but a Container. Now, how is Container defined? It could be e.g.
template <typename T>
struct Container: std::false_type { };
template <typename T, size_t N>
struct Container <std::array<T, N> >: std::true_type { };
template <typename T, typename A>
struct Container <std::vector<T, A> >: std::true_type { };
and so on. Predicates like Container exist now, but to integrate them into a template function requires inconvenient constructs like std::enable_if. Concepts will make this cleaner and easier to use.
This again, is just roughly my understanding.

Related

Why std::function has no function_type or equivalent member type?

From here it seems to me that the std::function has no function_type or equivalent member type to export the actual type used to initialize it.
It has result_type, argument_type, as well as first_argument_type and second_argument_type, but nothing like the type above mentioned.
Why it doesn't offer such a type as part of its interface?
There will be for sure a good reason for that, but I can't figure out what's that reason, so I'm just curious to find it out.
For I know the first question will be why do you need it, well, imagine that I want to do something like std::is_same<F1::function_type, F2::function_type>::value to check if their underlying types are the same in a sfinae evaluation, where it's fine if they contain different functions as long as the signs are the same.
I admit that it doesn't make much sense, to be honest the question is just for the sake of curiosity.
EDIT
As noted by #Brian in the comments of his answer, I misused the term initialize when I wrote:
to export the actual type used to initialize it
What I'm interested in is the template argument indeed.
As an example, for a std::function<void(S&, int)> (where S is a struct), function_type would be void(S&, int).
I think you're asking the wrong question. The right question is: why should there be such a member type?
If, say, you write a function template that can accept any specialization of std::function, then the template parameter will already be immediately available to you:
template <typename T>
void f(std::function<T> F) {
// you wouldn't write decltype(F)::function_type here; you'd just write T
}
The more inconvenient case is the one in which you have some function like
template <typename Callable>
void f(Callable C);
Here, you have no guarantee that Callable is a std::function specialization, so even if std::function<T> had typedef T function_type, you wouldn't want to access Callable::function_type for an arbitrary callable. So it wouldn't be of any use here.
The right question is: why do some standard library classes expose their template parameters, for example, containers of T (which have typedef T value_type)? The answer is that the standard has a specific set of requirements that the container types have to satisfy, which reflects a design goal that it should be possible to write generic algorithms that work on different types of containers, not all of which would be template specializations of the form C<T>. It then makes sense to mandate that all containers expose value_type because that's the only uniform way of extracting the element type from arbitrary containers.
If std::function were also an instance of some Callable concept, it would make sense to have the requirement that there is a function_type typedef so that code accepting any Callable could access the function type. But that's not the case, and it's not useful to have it for only the single template std::function.
You can easily write one:
template < typename T >
struct function_type;
template < typename Sig >
struct function_type<std::function<Sig>> { using type = Sig; };
On your terminology: instantiate is the word you're looking for. You are looking for the type that the template was instantiated with.
The only people who know why it isn't a member type are those who designed the feature and those who voted it in (maybe). It could simply be something nobody thought of. It does seem a bit obvious, but that's in hindsight from the perspective of wanting it.

Why specializing a type_trait could result in undefined behaviour?

Discussion
According to the standard §20.10.2/1 Header <type_traits> synopsis [meta.type.synop]:
1 The behavior of a program that adds specializations for any of the class templates defined in this subclause is undefined unless otherwise specified.
This specific clause contradicts to the general notion that STL should be expandible and prevents us from expanding type traits as in the example below:
namespace std {
template< class T >
struct is_floating_point<std::complex<T>> : std::integral_constant
<
bool,
std::is_same<float, typename std::remove_cv<T>::type>::value ||
std::is_same<double, typename std::remove_cv<T>::type>::value ||
std::is_same<long double, typename std::remove_cv<T>::type>::value
> {};
}
LIVE DEMO
where std::is_floating_point is expanded to handle complex number with underlying floating point type as well.
Questions
What are the reasons that made the standardization committee decide that type-traits should not be specialized.
Are there any future plans for this restriction to be retracted.
For the primary type categories, which is_floating_point is one, there is a design invariant:
For any given type T, exactly one of the primary type categories has
a value member that evaluates to true.
Reference: (20.10.4.1 Primary type categories [meta.unary.cat])
Programmers can rely on this invariant in generic code when inspecting some unknown generic type T: I.e. if is_class<T>::value is true, then we don't need to check is_floating_point<T>::value. We are guaranteed the latter is false.
Here is a diagram
representing the primary and composite type traits (the leaves at the top of this diagram are the primary categories).
http://howardhinnant.github.io/TypeHiearchy.pdf
If it was allowed to have (for example) std::complex<double> answer true to both is_class and is_floating_point, this useful invariant would be broken. Programmers would no longer be able to rely on the fact that if is_floating_point<T>::value == true, then T must be one of float, double, or long double.
Now there are some traits, where the standard does "say otherwise", and specializations on user-defined types are allowed. common_type<T, U> is such a trait.
For the primary and composite type traits, there are no plans to relax the restriction of specializing these traits. Doing so would compromise the ability of these traits to precisely and uniquely classify every single type that can be generated in C++.
Adding to Howard's answer (with an example).
If users were allowed to specialize type traits they could lie (intentionally or by mistake) and the Standard Library could no longer assure that its behavior is correct.
For instance, when an object of type std::vector<T> is copied an optimization that popular implementations do is calling std::memcpy to copy all elements provided that T is trivially copy constructible. They might use std::is_trivially_copy_constructible<T> to detect whether the optimization is safe or not. If not, then the implementation falls back to the safe but slower method which is looping through the elements and call T's copy constructor.
Now, if one specializes std::is_trivially_copy_constructible for T = std::shared_ptr<my_type> like this:
namespace std {
template <>
class is_trivially_copy_constructible<std::shared_ptr<my_type>> : std::true_type {
};
}
Then copying a std::vector<std::shared_ptr<my_type>> would be disastrous.
This would not be the Standard Library implementation's fault but rather the specialization writer's. To some extend, that's what the quote provided by the OP says: "It's your fault, not mine."

C++ concepts vs static_assert

What is exactly new in c++ concepts? In my understanding they are functionally equal to using static_assert, but in a 'nice' manner meaning that compiler errors will be more readable (as Bjarne Stroustup said you won't get 10 pages or erros, but just one).
Basically, is it true that everything you can do with concepts you can also achieve using static_assert?
Is there something I am missing?
tl;dr
Compared to static_asserts, concepts are more powerful because:
they give you good diagnostic that you wouldn't easily achieve with static_asserts
they let you easily overload template functions without std::enable_if (that is impossible only with static_asserts)
they let you define static interfaces and reuse them without losing diagnostic (there would be the need for multiple static_asserts in each function)
they let you express your intents better and improve readability (which is a big issue with templates)
This can ease the worlds of:
templates
static polymorphism
overloading
and be the building block for interesting paradigms.
What are concepts?
Concepts express "classes" (not in the C++ term, but rather as a "group") of types that satisfy certain requirements. As an example you can see that the Swappable concept express the set of types that:
allows calls to std::swap
And you can easily see that, for example, std::string, std::vector, std::deque, int etc... satisfy this requirement and can therefore be used interchangeably in a function like:
template<typename Swappable>
void func(const Swappable& a, const Swappable& b) {
std::swap(a, b);
}
Concepts always existed in C++, the actual feature that will be added in the (possibly near) future will just allow you to express and enforce them in the language.
Better diagnostic
As far as better diagnostic goes, we will just have to trust the committee for now. But the output they "guarantee":
error: no matching function for call to 'sort(list<int>&)'
sort(l);
^
note: template constraints not satisfied because
note: `T' is not a/an `Sortable' type [with T = list<int>] since
note: `declval<T>()[n]' is not valid syntax
is very promising.
It's true that you can achieve a similar output using static_asserts but that would require different static_asserts per function and that could get tedious very fast.
As an example, imagine you have to enforce the amount of requirements given by the Container concept in 2 functions taking a template parameter; you would need to replicate them in both functions:
template<typename C>
void func_a(...) {
static_assert(...);
static_assert(...);
// ...
}
template<typename C>
void func_b(...) {
static_assert(...);
static_assert(...);
// ...
}
Otherwise you would loose the ability to distinguish which requirement was not satisfied.
With concepts instead, you can just define the concept and enforce it by simply writing:
template<Container C>
void func_a(...);
template<Container C>
void func_b(...);
Concepts overloading
Another great feature that is introduced is the ability to overload template functions on template constraints. Yes, this is also possible with std::enable_if, but we all know how ugly that can become.
As an example you could have a function that works on Containers and overload it with a version that happens to work better with SequenceContainers:
template<Container C>
int func(C& c);
template<SequenceContainer C>
int func(C& c);
The alternative, without concepts, would be this:
template<typename T>
std::enable_if<
Container<T>::value,
int
> func(T& c);
template<typename T>
std::enable_if<
SequenceContainer<T>::value,
int
> func(T& c);
Definitely uglier and possibly more error prone.
Cleaner syntax
As you have seen in the examples above the syntax is definitely cleaner and more intuitive with concepts. This can reduce the amount of code required to express constraints and can improve readability.
As seen before you can actually get to an acceptable level with something like:
static_assert(Concept<T>::value);
but at that point you would loose the great diagnostic of different static_assert. With concepts you don't need this tradeoff.
Static polymorphism
And finally concepts have interesting similarities to other functional paradigms like type classes in Haskell. For example they can be used to define static interfaces.
For example, let's consider the classical approach for an (infamous) game object interface:
struct Object {
// …
virtual update() = 0;
virtual draw() = 0;
virtual ~Object();
};
Then, assuming you have a polymorphic std::vector of derived objects you can do:
for (auto& o : objects) {
o.update();
o.draw();
}
Great, but unless you want to use multiple inheritance or entity-component-based systems, you are pretty much stuck with only one possible interface per class.
But if you actually want static polymorphism (polymorphism that is not that dynamic after all) you could define an Object concept that requires update and draw member functions (and possibly others).
At that point you can just create a free function:
template<Object O>
void process(O& o) {
o.update();
o.draw();
}
And after that you could define another interface for your game objects with other requirements. The beauty of this approach is that you can develop as many interfaces as you want without
modifying your classes
require a base class
And they are all checked and enforced at compile time.
This is just a stupid example (and a very simplistic one), but concepts really open up a whole new world for templates in C++.
If you want more informations you can read this nice article on C++ concepts vs Haskell type classes.

Does C++11 support types recursion in templates?

I want to explain the question in detail. In many languages with strong type systems (like Felix, Ocaml, Haskell) you can define a polymorphic list by composing type constructors. Here's the Felix definition:
typedef list[T] = 1 + T * list[T];
typedef list[T] = (1 + T * self) as self;
In Ocaml:
type 'a list = Empty | Cons ('a, 'a list)
In C, this is recursive but neither polymorphic nor compositional:
struct int_list { int elt; struct int_list *next; };
In C++ it would be done like this, if C++ supported type recursion:
struct unit {};
template<typename T>
using list<T> = variant< unit, tuple<T, list<T>> >;
given a suitable definition for tuple (aka pair) and variant (but not the broken one used in Boost). Alternatively:
using list<T> = variant< unit, tuple<T, &list<T>> >;
might be acceptable given a slightly different definition of variant. It was not possible to even write this in C++ < C++11 because without template typedefs, there's no way to get polymorphism, and without a sane syntax for typedefs, there's no way to get the target type in scope. The using syntax above solves both these problems, however this does not imply recursion is permitted.
In particular please note that allowing recursion has a major impact on the ABI, i.e. on name mangling (it can't be done unless the name mangling scheme allows for representation of fixpoints).
My question: is required to work in C++11?
[Assuming the expansion doesn't result in an infinitely large struct]
Edit: just to be clear, the requirement is for general structural typing. Templates provide precisely that, for example
pair<int, double>
pair<int, pair <long, double> >
are anonymously (structurally) typed, and pair is clearly polymorphic. However recursion in C++ < C++11 cannot be stated, not even with a pointer. In C++11 you can state the recursion, albeit with a template typedef (with the new using syntax the expression on the LHS of the = sign is in scope on the RHS).
Structural (anonymous) typing with polymorphism and recursion are minimal requirements for a type system.
Any modern type system must support polynomial type functors or the type system is too clumbsy to do any kind of high level programming. The combinators required for this are usually stated by type theoreticians like:
1 | * | + | fix
where 1 is the unit type, * is tuple formation, + is variant formation, and fix is recursion. The idea is simply that:
if t is a type and u is a type then t + u and t * u are also types
In C++, struct unit{} is 1, tuple is *, variant is + and fixpoints might be obtained with the using = syntax. It's not quite anonymous typing because the fixpoint would require a template typedef.
Edit: Just an example of polymorphic type constructor in C:
T* // pointer formation
T (*)(U) // one argument function type
T[2] // array
Unfortunately in C, function values aren't compositional, and pointer formation is subject to lvalue constraint, and the syntactic rules for type composition are not themselves compositional, but here we can say:
if T is a type T* is a type
if T and U are types, T (*)(U) is a type
if T is a type T[2] is a type
so these type constuctors (combinators) can be applied recursively to get new types without having to create a new intermediate type. In C++ we can easily fix the syntactic problem:
template<typename T> using ptr<T> = T*;
template<typename T, typename U> using fun<T,U> = T (*)(U);
template<typename T> using arr2<T> = T[2];
so now you can write:
arr2<fun<double, ptr<int>>>
and the syntax is compositional, as well as the typing.
No, that is not possible. Even indirect recursion through alias templates is forbidden.
C++11, 4.5.7/3:
The type-id in an alias template declaration shall not refer to the alias template being declared. The type produced by an alias template specialization shall not directly or indirectly make use of that specialization. [ Example:
template <class T> struct A;
template <class T> using B = typename A<T>::U;
template <class T> struct A {
typedef B<T> U;
};
B<short> b; // error: instantiation of B<short> uses own type via A<short>::U
— end example ]
If you want this, stick to your Felix, Ocaml, or Haskell. You will easily realize that very few (none?) sucessful languages have type systems as rich as those three. And in my opinion, if all languages were the same, learning new ones wouldn't be worth it.
template<typename T>
using list<T> = variant< unit, tuple<T, list<T>> >;
In C++ doesn't work because an alias template doesn't define a new type. It's purely an alias, a synonym, and it is equivalent to its substitution. This is a feature, btw.
That alias template is equivalent to the following piece of Haskell:
type List a = Either () (a, List a)
GHCi rejects this because "[cycles] in type synonym declarations" are not allowed. I'm not sure if this is outright banned in C++, or if it is allowed but causes infinite recursion when substituted. Either way, it doesn't work.
The way to define new types in C++ is with the struct, class, union, and enum keywords. If you want something like the following Haskell (I insist on Haskell examples, because I don't know the other two languages), then you need to use those keywords.
newtype List a = List (Either () (a, List a))
I think you may need to review your type theory, as several of your assertions are incorrect.
Let's address your main question (and backhanded point) - as others have pointed out type recursion of the type you requested is not allowed. This does not mean that c++ does not support type recursion. It supports it perfectly well. The type recursion you requested is type name recursion, which is a syntactic flair that actually has no consequence on the actual type system.
C++ allows tuple membership recursion by proxy. For instance, c++ allows
class A
{
A * oneOfMe_;
};
That is type recursion that has real consequences. (And obviously no language can do this without internal proxy representation because size is infinitely recursive otherwise).
Also C++ allows translationtime polymorphism, which allow for the creation of objects that act like any type you may create using name recursion. The name recursion is only used to unload types to members or provide translationtime behavior assignments in the type system. Type tags, type traits, etc. are well known c++ idioms for this.
To prove that type name recursion does not add functionality to a type system, it only needs to be pointed out that c++'s type system allows a fully Turing Complete type calculation, using metaprogramming on compiletime constants (and typelists of them), through simple mapping of names to constants. This means there is a function MakeItC++:YourIdeaOfPrettyName->TypeParametrisedByTypelistOfInts that makes any Turing computible typesystem you want.
As you know, being a student of type theory, variants are dual to tuple products. In the type category, any property of variants has a dual property of tuple products with arrows reversed. If you work consistently with the duality, you do not get properties with "new capabilities" (in terms of type calculations). So on the level of type calculations, you obviously don't need variants. (This should also be obvious from the Turing Completeness.)
However, in terms of runtime behavior in an imperative language, you do get different behavior. And it is bad behavior. Whereas products restrict semantics, variants relax semantics. You should never want this, as it provably destroys code correctness. The history of statically typed programming languages has been moving towards greater and greater expression of the semantics in the type system, with the goal that the compiler should be able to understand when the program does not mean what you want it to. The goal has been to turn the compiler into the program verification system.
For instance, with type units, you can express that a particular value isn't just an int but is actually an acceleration measured in meters per square seconds. Assigning a value that is a velocity expressed in feet per hour divided by a timespan of minutes shouldn't just divide the two values - it should note that a conversion is necessary (and either perform it or fail compilation or... do the right thing). Assinging a force should fail compilation. Doing these kinds of checks on program meaning could have given us potentially more martian exploration, for instance.
Variants are the opposite direction. Sure, "if you code correctly, they work correctly", but that's not the point with code verification. They provably add code loci where a different engineer, unfamiliar with current type usage, can introduce the incorrect semantic assumption without translation failure. And, there is always a code transformation that changes an imperative code section from one that uses Variants unsafely to one that use semantically validated non-variant types, so their use is also "always suboptimal".
The majority of runtime uses for variants are typically those that are better encapsulated in runtime polymorphism. Runtime polymorphism has a statically verified semantics that may have associated runtime invariant checking and unlike variants (where the sum type is universally declared in one code locus) actually supports the Open-Closed principle. By needing to declare a variant in one location, you must change that location everytime you add a new functional type to the sum. This means that code never closes to change, and therefore may have bugs introduced. Runtime polymorphism, though, allows new behaviors to be added in separate code loci from the other behaviors.
(And besides, most real language type systems are not distributive anyway. (a, b | c) =/= (a, b) | (a, c) so what is the point here?)
I would be careful making blanket statements about what makes a type system good without getting some experience in the field, particularly if your point is to be provocative and political and enact change. I do not see anything in your post that actually points to healthy changes for any computer language. I do not see features, safety, or any of the other actual real-world concerns being addressed. I totally get the love of type theory. I think every computer scientist should know Cateogry Theory and the denotational semantics of programming languages (domain theory, cartesian categories, all the good stuff). I think if more people understood the Curry-Howard isomorphism as an ontological manifesto, constructivist logics would get more respect.
But none of that provides reasons to attack the c++ type system. There are legitimate attacks for nearly every language - type name recursion and variant availability are not them.
EDIT: Since my point about Turing completeness does not seem to be understood, nor my comment about the c++ way of using type tags and traits to offload type calculations, maybe an example is in order.
Now the OP claims to want this in a usage case for lists, which my earlier point on the layout easily handles. Better, just use std::list. But from other comments and elsewhere, I think they really want this to work on the Felix->C++ translation.
So, what I think the OP thinks they want is something like
template <typename Type>
class SomeClass
{
// ...
};
and then be able to build a type
SomeClass< /*insert the SomeClass<...> type created here*/ >
I've mentioned this is just a naming convention wanted. Nobody wants typenames - they are transients of the translation process. What is actually wanted is what you will do with Type later on in the structural composition of the type. It will be used in typename calculations to produce member data and method signatures.
So, what can be done in c++ is
struct SelfTag {};
Then, when you want to refer to self, just put this type tag there.
When it's meaningful to do the type calculation, you have a template specialisation on SelfTag that will substitute SomeClass<SelfTag> instead of substituting SelfTag in the appropriate place of the type calculation.
My point here is that the c++ type system is Turing Complete - and that means a lot more than what I think the OP is reading everytime I've written that. Any type calculation may be done (given constraints of compiler recursion) and that really does mean that if you have a problem in one type system in a completely different language, you can find a translation here. I hope this makes things even clearer about my point. Coming back and saying "well you still can't do XYZ in the type system" would be clearly missing the point.
C++ does have the "curiously recurring template pattern", or CRTP. It's not specific to C++11, however. It means you can do the following (shamelessly copied from Wikipedia):
template <typename T>
struct base
{
// ...
};
struct derived : base<derived>
{
// ...
};
#jpalcek answered my question. However, my actual problem (as hinted at in the examples) can be solved without recursive aliases like this:
// core combinators
struct unit;
struct point;
template<class T,class U> struct fix;
template<class T, class U> struct tup2;
template<class T, class U> struct var2;
template <> struct
fix<
point,
var2<unit, tup2<int,point> >
>
{
// definition goes here
};
using the fix and point types to represent recursion. I happen not to require any of the templates to be defined, I only need to define the specialisations. What I needed was a name that would be the same in two distinct translation units for external linkage: the name had to be a function of the type structure.
#Ex0du5 prompted thinking about this. The actual solution is also related to a correspondence from Gabriel des Rois many years ago. I want to thank everyone that contributed.

Hypothetical, formerly-C++0x concepts questions

(Preamble: I am a late follower to the C++0x game and the recent controversy regarding the removal of concepts from the C++0x standard has motivated me to learn more about them. While I understand that all of my questions are completely hypothetical -- insofar as concepts won't be valid C++ code for some time to come, if at all -- I am still interested in learning more about concepts, especially given how it would help me understand more fully the merits behind the recent decision and the controversy that has followed)
After having read some introductory material on concepts as C++0x (until recently) proposed them, I am having trouble wrapping my mind around some syntactical issues. Without further ado, here are my questions:
1) Would a type that supports a particular derived concept (either implicitly, via the auto keyword, or explicitly via concept_maps) also need to support the base concept indepdendently? In other words, does the act of deriving a concept from another (e.g. concept B<typename T> : A<T>) implicitly include an 'invisible' requires statement (within B, requires A<T>;)? The confusion arises from the Wikipedia page on concepts which states:
Like in class inheritance, types that
meet the requirements of the derived
concept also meet the requirements of
the base concept.
That seems to say that a type only needs to satisfy the derived concept's requirements and not necessarily the base concept's requirements, which makes no sense to me. I understand that Wikipedia is far from a definitive source; is the above description just a poor choice of words?
2) Can a concept which lists typenames be 'auto'? If so, how would the compiler map these typenames automatically? If not, are there any other occasions where it would be invalid to use 'auto' on a concept?
To clarify, consider the following hypothetical code:
template<typename Type>
class Dummy {};
class Dummy2 { public: typedef int Type; };
auto concept SomeType<typename T>
{
typename Type;
}
template<typename T> requires SomeType<T>
void function(T t)
{}
int main()
{
function(Dummy<int>()); //would this match SomeType?
function(Dummy2()); //how about this?
return 0;
}
Would either of those classes match SomeType? Or is a concept_map necessary for concepts involving typenames?
3) Finally, I'm having a hard time understanding what axioms would be allowed to define. For example, could I have a concept define an axiom which is logically inconsistent, such as
concept SomeConcept<typename T>
{
T operator*(T&, int);
axiom Inconsistency(T a)
{
a * 1 == a * 2;
}
}
What would that do? Is that even valid?
I appreciate that this is a very long set of questions and so I thank you in advance.
I've used the most recent C++0x draft, N2914 (which still has concepts wording in it) as a reference for the following answer.
1) Concepts are like interfaces in that. If your type supports a concept, it should also support all "base" concepts. Wikipedia statement you quote makes sense from the point of view of a type's client - if he knows that T satisfies concept Derived<T>, then he also knows that it satisfies concept Base<T>. From type author perspective, this naturally means that both have to be implemented. See 14.10.3/2.
2) Yes, a concept with typename members can be auto. Such members can be automatically deduced if they are used in definitions of function members in the same concept. For example, value_type for iterator can be deduced as a return type of its operator*. However, if a type member is not used anywhere, it will not be deduced, and thus will not be implicitly defined. In your example, there's no way to deduce SomeType<T>::Type for either Dummy or Dummy1, as Type isn't used by other members of the concept, so neither class will map to the concept (and, in fact, no class could possibly auto-map to it). See 14.10.1.2/11 and 14.10.2.2/4.
3) Axioms were a weak point of the spec, and they were being constantly updated to make some (more) sense. Just before concepts were pulled from the draft, there was a paper that changed quite a bit - read it and see if it makes more sense to you, or you still have questions regarding it.
For your specific example (accounting for syntactic difference), it would mean that compiler would be permitted to consider expression (a*1) to be the same as (a*2), for the purpose of the "as-if" rule of the language (i.e. the compiler permitted to do any optimizations it wants, so long as the result behaves as if there were none). However, the compiler is not in any way required to validate the correctness of axioms (hence why they're called axioms!) - it just takes them for what they are.