What is the difference between "Generics" (Java/C#) and "template" (C++)

Asked

Viewed 739 times

19

1 answer

18


I will not go into detail about the paradigm already answered in What is generic programming?.

For a more detailed comparison only of generics can already be seen in the aforementioned question.

Generics are used in many modern languages such as D, Rust, Swift, Typescript, VB.NET, Delphi, Objective C, Eiffel, Ada, Hack, F# and other diverse functional languages, etc. in fact any language that wants to give total security of types needs to have this mechanism or will have very little flexibility.

The jigs (templates) are used to allow the use of generics, among other things. This is another form similar to the parametric polymorphism, but not equal.

Why are there

In dynamic typing languages it is easy to create an algorithm that serves several data structures (different types). When static typing is used it is necessary to replicate the identical algorithms or even other structures that use some data to compose. This is usually absurd.

A commonly used trick is to create a indirect (pointer) and a wildcard type. The problem with this is that this indirect may be unwanted in some cases and there is no longer type security making the language virtually dynamic typing in such cases.

The solution was to create this Generics that is nothing more than a parameterization of the data type to be used at some point in a data structure (class for example) or algorithm (function). So the programmer writes once and the compiler gives a way to use this definition with different types safely and almost always quickly.

The templates of C++ serve for this and a little more. It is more powerful and flexible allowing what is often called metaprogramming. So the main goal of both is the same, but the templates go beyond.

Difference TL;DR

We must understand Generics as a solution only for parameterization of types while templates are a solution, roughly, to replace C macros in a more comfortable, powerful and secure way, allowing virtually everything that Generics allows and much more. In the implementation of C++ there is the goal of not generating any additional costs in the execution.

Characteristic C++ C# Java
Instantiation Compilation Execution You don’t have to
Type safety Yes (almost) Yes Yes
Turing Complete Language Yes Not Not
You need the source code Yes Not Not
Typical build time Long Short Short
Code list: instances (types per value) 1:1 1:1 Impossible
Code list: instances (by reference) 1:1 1:N 1:N
Parameterization of types Yes Yes Yes
Parameterization of values Yes Not Not
Default values and types Multiple Not Not
Understandable error messages Not always Good Good
Easy to debug Not Yes Reasonable
Expertise Yes Not Not
Partial specialisation/mixing Yes Not Not
Recursive instantiation Yes Not Not
Instantiation restrictions with subtype Not Yes Yes
Restrictions on specialisation Yes Not Not
Ease to create generics Not always Yes Yes

Detailing

The first big difference is that the templates are resolved fully at compile time. No trace of them are left to run time. Helps in the performance of the application, but increases the size of the code, since each specialized instance needs to be created in the executable, and does not give more information for debugging, after all in the code there are not all these instances of classes and/or functions (note that instance here is not object, but generic code). Of course the source code is needed because of this. That’s one of the reasons the build is slower.

But it is slow also because it allows to do much more, has a lot of complicated situation to analyze. The system of templates itself is considered a full programming language, allowing you to create complete codes. See a classic example that is exaggerated to do, but it is possible:

template <int N>
struct factorial {
  enum { value = N * factorial<N - 1>::value };
};

template <>
struct factorial<0> {
  enum { value = 1 };
};

enum { result = factorial<5>::value }; // 5 * 4 * 3 * 2 * 1 == 120

I put in the Github for future reference.

Then we noticed two extra features of templates. Allows recursion and accepts parameterization of values, in addition to types. Could put a value default, so the value could be omitted at the specific value instantiation. The same goes for a type, so if an instance of a generic function or type could be created even without specifying what type it should be - a utility much less than the value default.

There are even manual techniques to take advantage of an instance for several types by reference (to do by value will add a probably unwanted indirect)but the normal is that each specific type with the potential to be used will generate an independent code for each combination of parameters used. With one parameter you can create too much code, imagine with several.

C# does the same for types by value, but for types by reference that would already have a natural indirect it reuses. Anyway, C# only creates the instance if it is actually used at runtime, which generates a overhead to the Jitter. Java can only do it in types by reference (until the date I wrote it) and you don’t need to create instances, there will always be only one. The problem with that is you need to do it Casts (even if the compiler automatically puts it by the programmer) and usually generates inefficiencies.

Note that the mechanism of template is a code generator. It takes a code with parameters, swapping for arguments defined at the generic resource instantiation. You can do almost anything. This flexibility creates some confusion. It’s easy to abuse. Because of this in various situations the generated code error messages are very confusing (it is improving a lot).

Something cool about those templates is that they can be specialized. Then you can have a specific type or value with a different implementation of your own than defined in the generic (as in the example above). You can do this with parts, including bringing from another code creating mixins. This is very strong, making the resource much more useful and being able to generalize much more things because it can even treat cases that are exceptions. And it is possible to restrict what you use in specialization. You can even say that you can only do if a particular operation is available. There are known design patterns that get very easy and performative if done with templates.

Newer versions of C++ and future proposals aim to extend the ability to create restrictions on what can be instantiated. Today this is a disadvantage. There is a case that compiles even what cannot be executed, losing a little the security that should give. Pure generics have a subtype-based form of restriction indicating which types can be instantiated, ensuring total security.

Templates have a system of own heritage that allows some very sophisticated techniques and difficult to do right.

  • I must say that I read an article (I think 2017) that showed that the Generics of Java was Turing Complete, I go after the source so I can update the table if the source is confirmed

  • Yeah, I saw someone talking about it.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.