What are the differences between Generics in C# and Java… and Templates in C++?
Hi all,
I am experienced C++ programmer but quite new to C#.
Whats up with those constraints and generics? Why doesn't it work the same as in C++ where constraints are implicit and derived from the instantiations you do to the template class?
Why didn't Microsoft make it work the same way as in C++?
C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...
In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr.
Compared to other languages—like Java, PHP, or C#—C is a relatively simple language to learn for anyone just starting to learn computer programming because of its limited number of keywords.
C is an imperative procedural language supporting structured programming, lexical variable scope, and recursion, with a static type system. It was designed to be compiled to provide low-level access to memory and language constructs that map efficiently to machine instructions, all with minimal runtime support.
Well, in general, C++ templates and C# generics are similar - compared to Java generics which are completely different, but they have also large differences. Like in C#, there is runtime support by using reflection, getting an object describing the types used to instantiate a generics. C++ doesn't have reflection, and all it does with types is done at compile time.
The biggest difference between C# generics and C++ templates indeed are that C# generics are better type checked. They are always constrained, in the sense that they don't allow operations that are not stated valid at the time of defining the generics. C#'s chief designer raised as a reason of that the added complexity it would have taken to have implied constraints. I'm not well versed with C#, so i can't talk further here. I'll talk about about how matters are in C++ and how they are going to be improved, so that people don't think C++'s stuff is all wrong.
In C++, templates are not constrained. If you do an operation, at template definition time it is implied that the operation will succeed at instantiation time. It's not even required to a C++ compiler that the template is syntactically checked for validity. If it contains a syntax error, then that error has to be diagnosed at instantiation. Any diagnose before that is a pure goody of the implementation.
Those implied constraint have shown to be easy for the template designer in the short term, because they don't have to care about stating the valid operations in their template interface. They put the burden on the user of their template - so the user has to make sure he fulfills all those requirements. Often it happens that the user tries seemingly valid operations but fails, with the compiler giving the user hundreds of lines of error messages about some invalid syntax or not found names. Because the compiler can't know what constraint in particular was violated in the first place, it lists all parts of code paths ever involved around the faulty place and all not even important details, and the user will have to crawl through the horrible error message text.
That is a fundamental problem, which can be solved by just stating at the interface for a template or generics what properties a type parameter has to have. C#, as far as i know it, can constraint the parameter to implement an interface or inherit a base-class. It solves that on a type-level.
The C++ committee has long seen there is need to fix these problems, and soon (next year, probably), C++ will have a way to state such explicit constraints too (see time-machine note below), as in the following case.
template<typename T> requires VariableType<T>
T f(T a, T b) {
return a + b;
}
The compiler signals an error at that point, because the expression as written is not marked valid by the requirements. This first helps the designer of the template to write more correct code, because the code is type-checked already to some degree (well to what is possible there). The programmer can now state that requirement:
template<typename T> requires VariableType<T> && HasPlus<T, T>
T f(T a, T b) {
return a + b;
}
Now, it will compiler. The compiler, by seeing T
appearing as the return type, automatically implied that T
is copyable, because that use of T
appears in the interface, rather than in the templates body. The other requirements were stated using requirement clauses. Now, the user will get a appropriate error message if he uses a type that doesn't have an op+
defined.
C++1x decouples the requirements from the type. The above works for primitive types aswell as for classes. In this sense, they are more flexible, but quite a bit complex. The rules that state when and when requirements are satisfied are long... You can with the new rules say the following:
template<typename T> requires MyCuteType<T>
void f(T t) { *t = 10; }
And then, call f
with an int
! That would work by just writing a concept map for MyCuteType<int>
that teaches the compiler how an int can be dereferenced. It will get quite handy in loops like this:
for_each(0, 100, doSomething());
Since the programmer can tell the compiler how an int can satisfy the concept of an input iterator
, you could actually write such code in C++1x, if you only write the appropriate concept map, which really isn't all that difficult.
Ok, enough with this. I hope i could show you that having templates constrained is not all that bad, but in fact better, because the relationship betweens types and the operations on them within the templates are now known by the compiler. And i haven't even written about axioms
, which are another nice thing in C++1x
' concepts. Remember that this is future stuff, it's not yet out, but it will approximately at 2010. Then we will have to wait for some compiler to implement that all :)
C++0x concepts were not accepted into the draft but have been voted out at late of 2009. Too bad! But perhaps we will see it again in the next C++ version? Let's all hope!
C++ templates: The compiler checks whether the arguments satisfy the constraints set by the code. For example:
template <typename T, unsigned int dim>
class math_vector
{
T elements[dim];
math_vector<T,dim> operator+ (const math_vector<T,dim>& other) const
{
math_vector<T,dim> result;
for (unsigned int i = 0; i < dim; ++i)
result.elements[i] = elements[i] + other.elements[i];
}
}
struct employee
{
char name[100];
int age;
float salary;
}
math_vector<int, 3> int_vec; //legal
math_vector<float, 5> float_vec; //legal
math_vector<employee, 10> employee_vec; //illegal, operator+ not defined for employee
In this example, you could create a class, define operator+
for it and use it as a parameter for math_vector
. Therefore, a template parameter is valid if and only if it satisfies the constraints defined by the template's code. This is very flexible, but results in long compilation times (whether a type satisfies the template's constraints must be checked every time the template is instantiated).
C# generics: Instead of checking the validity of every particular instantiation, which results in longer compile times and is error prone, you declare explicitly that the generic's arguments must implement a particular interface (a set of methods, properties and operators). Inside the generic's code, you can't call any methods freely, but only those supported by that interface. Every time you instantiate a generic, the runtime doesn't have to check whether the argument satisfies a long set of constraints, but only whether it implements the specified interface. Of course, this is less flexible, but it's less error prone, too. Example:
class SortedList<T> where T : IComparable<T>
{
void Add(T i) { /* ... */ }
}
class A : IComparable<A> { /* ... */ }
class B
{
int CompareTo(B b) { /* ... */ }
bool Equals(B b) { /* ... */ }
}
SortedList<A> sortedA; // legal
SortedList<B> sortedB; // illegal
// B implements the methods and properties defined in IComparable,
// however, B doesn't explicitly implement IComparable<B>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With