20

I understand the aspects of templates in C++ that are different from generics in Java and C#. C# is a reification, Java uses type erasure, C++ uses duck typing, etc. There are a number of things C++ templates can do that Java and C# generics can't (e.g. template specialization). But there are a number of things Java generics can do that C# and C++ can't (e.g. make a bounded type parameter of a family of generics like class Foo<T extends Comparable<?>>), and a number of things C# generics can do that Java and C++ can't (e.g. runtime generic reflection). [EDIT: Apparently Java generics are much weaker than I thought. (Which is saying something.) In any case, despite their ineptness, they are still considered generics along with C#'s generics.]

What I don't understand is what conceptually makes templates different from generics. What parts of C++ templates are things that cannot be done in something that isn't a template, but is a generic? For example, if I were to implement a language that supported templates, what would absolutely need to be in it? What could I leave out that would be necessary for the language to support generics?

My guess is that templates are a super-set of generics or they are a way to implement generics, but I don't really understand what separates a true template from a true generic.

Eva
  • 4,397
  • 5
  • 43
  • 65
  • 7
    Both generics and templates allow the same source code to be used with different types. The main difference is with what the source code is compiled to. In short: Generics = same bytecode code for *all* types (that meet the constraints); Templates = different machine code for *each* type actually used. – dtb Mar 26 '13 at 10:43
  • So generics and templates are two approaches to the same problem (use the same source code with different types), but none is a super-set of the other. For generics, C# and Java again follow different approaches, with C# having runtime support for generics while Java having not. – dtb Mar 26 '13 at 10:53
  • You have a factual inaccuracy. Bounded type parameters in Java approximate generic type constraints in C#. – spender Mar 26 '13 at 11:03
  • @spender It's not the bounded parameters by themselves that's unique to Java. Java allows you to use them in combination with wildcards, but C# does not have wildcards. Wildcards allow you to specify a family of generics. My Java example in C# would have to be `class Foo where T : Comparable`. – Eva Mar 26 '13 at 11:11
  • @dtb C# Generates separate bytecode for instantiations on value types. E.g. List and List do not share byte code. – Sjoerd Mar 26 '13 at 12:05
  • This blog of Eric Lippert might qualify as an answer: http://blogs.msdn.com/b/ericlippert/archive/2009/07/30/generics-are-not-templates.aspx – Sjoerd Mar 26 '13 at 12:06
  • I'd like to point out that you seem to be mistaken in thinking that the term 'generic' means anything specific in relation to templates. Different languages use terms to mean different things. For example, Ada had generics well before C++, Java, or C# had any generic facilities whatsoever. Despite being called 'generics', Ada's generics are much closer to C++ templates than anything Java or C# do. – Ryan Witmer Mar 26 '13 at 14:44
  • @RyanWitmer According to [Wikipedia](http://en.wikipedia.org/wiki/Generic_programming#Generics_in_Ada) the only difference between C++ templates and Ada generics is template specialization. It's also what makes TMP Turing complete. Thanks. I think I have my answer now :) – Eva Mar 26 '13 at 15:09

6 Answers6

10

Hm.. if you say you understand C++ templates in depth and say that you don't see/feel the difference between generics and them, well, that most probably you are right :)

There are many differences that will describe how/why generics are better than templates, list tons of differences, etc, but that's mostly irrelevant to the core of the idea.

The idea is to allow better code reuse. Templates/generics provide you a way to build a some kind of higher-order class definitions that abstract over some of the actual types.

In this terms, there is no difference between them, and the only differences are those enforced by specific features and constraints of the underlying language and runtime.

One may argue that generics provide some extra features (usually when talking about dynamic introspection of object's class tree), but very few of them (if any at all) cannot be implemented manually in C++'s templates. With some effort, most of them can be implemented, or emulated, hence they are not good as a distinction between 'proper generics' and 'real templates'.

Others will argue that the sheer potential power of optimization that is available thanks to the C++'s copy-paste behavior is the difference. Sorry, not true. JITs in Java and C# can do it too, well, almost, but do it very well.

There is however one thing that really could make the Java/C#'s generics a true subset of C++'s templates features. And you even have mentioned it!

It is template specialization.

In C++, each specialization behaves as a completely different definition.

In C++, template<typename T> Foo specialized to T==int may look like:

class Foo<int> 
{
    void hug_me();

    int hugs_count() const;
}

while "the same" template specialized to T==MyNumericType may look like

class Foo<MyNumericType> 
{
    void hug_me();

    MyNumericType get_value() const;
    void  reset_value() const;
}

FYI: that's just pseudocode, won't compile:)

Neither Java's nor C#'s generics can do that, because their definition states that all generic-type-materializations will have the same "user interface".

More to it, C++ uses a SFINAE rule. Many "theoretically colliding" specializations' definitions may exist for a template. However, when the template is being used, only those "actually good" are used.

With classes similar to the example above, if you use:

 Foo<double> foood;
 foood.reset_value();

only the second specialization would be used, as the first one would not compile because of ... "reset_value" missing.

With generics, you cannot do that. You'd need to create a generic class that has all possible methods, and then that would at runtime dynamically inspect the inner objects and throw some 'not implemented' or 'not supported' exceptions for unavailable methods. That's... just awful. Such things should be possible at compile-time.

The actual power, implications, problems and overall complexity of template specialization and SFINAE is what truly differentiates the generics and templates. Simply, generics are defined in a such way, that specialization is not possible, hence SFINAE is not possible, hence, the whole mechanism is paradoxically much easier/simplier.

Both easier/simplier to implement in the compiler's internals, and to be understood by non-savant brains.

Although I agree with the overall benefits of generics in Java/C#, I really miss the specializations, interface flexibility, and SFINAE rule. However, I would not be fair if I'd not mention one important thing related to sane OO design: if you template-specialization for type xxx actually changes it's client API, then most probably it should be named differently and should form a different template. All the extra goodies that templates can do were mostly added to the tools set because ... in C++ there was no reflection and it had to be emulated somehow. SFINAE is a form of compile-time reflection.

Hence, the biggest player in the world of differences gets reduced to a curious (beneficial) sideeffect of a hotfix applied to mask the runtime's deficiency, which is the almost complete lack of runtime introspection :))

Therefore, I say that there are no difference other than some arbitrary ones enforced by laguage, or some arbitrary ones enforced by the runtime platform.

All of them are just a form of higher-order classes or functions/methods, and I think that this is the most important thing and feature.

EHuhtala
  • 587
  • 3
  • 8
quetzalcoatl
  • 32,194
  • 8
  • 68
  • 107
  • 3
    *one important thing related to sane OO design*... Templates are a different paradigm than OO. If you try to look at templates with OO glasses you won't see the details that matter, or you won't like what you see. – David Rodríguez - dribeas Mar 26 '13 at 13:31
  • I absolutely agree! That's why I said "most probably" and "client API", because if you make a vector<> specialisation that will quack instead of holding objects, then it should be a 'duck', not 'vector':) or 'quacktor' atleast.. – quetzalcoatl Mar 26 '13 at 14:53
  • Uhm... interesting that you bring that particular example, since there **is** an specialization of `std::vector<>` for `bool` in the standard that *quacks* like a vector but does not store the objects like a vector... – David Rodríguez - dribeas Mar 26 '13 at 15:03
  • I think you've misunderstood my intent.. That spec of vector actually _stores_ values (somehow) and _provides API_ of a typical vector. Hence, it is a proper vector even in terms of OO. In terms of OO, what the implementation performs internally is irrelevant as long as the published API is fulfilled. By "quack" I meant "something completely different" like removing .size .at .push methods and providing literally .quack .move .fly - what is usually completely possible with template specializations :) – quetzalcoatl Mar 26 '13 at 15:26
  • 1
    I think we are saying the same thing in different ways. Specializations allow for proper modifications of the object that still fall somehow within the same protocol (although not exactly, `std::vector::front()` returns `T&` for any type other than `bool` but returns a proxy object if the stored type is `bool`. This is a valid use for specializations. Of course you can abuse it and break it in the same way that you can with plain inheritance if you narrow the contract of the derived type) – David Rodríguez - dribeas Mar 26 '13 at 15:45
4

First, I find it interesting that RTTI/introspection is a big part of most of the answers. Well, that is not a difference of generics vs. templates, but rather languages with instrospection vs. languages that don't have it. Otherwise you can also claim that to be a difference of C++ classes with Java classes, and C++ functions with Java functions...

If you take instrospection out of the way, the main difference is that templates define a turing complete language, functional in style although with a horrible grammar at it on which you can program. The first really complex example I heard of (I would love having the code, but I don't) was a program that calculated prime numbers at compile time. Which does bring another difference: templates can take type arguments, or template arguments or non-type arguments (non-type refers to anything that is not a type or a template, like an int value).

This has been mentioned in other answers, but just saying that templates can be specialized and that there is SFINAE does not clearly state that those two features are sufficient to generate a turing complete language.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • Did a little bit of hunting. Apparently the [primes program](http://en.wikibooks.org/wiki/C%2B%2B_Programming/Templates/Template_Meta-Programming#History_of_TMP) was the first TMP program. It printed the primes **as a compile-time error message** O_o – Eva Mar 26 '13 at 13:55
3

there are a number of things Java generics can do that C# and C++ can't (e.g. make a bounded type parameter of a family of generics like class Foo<T extends Comparable<?>>)

Not entirely true for that example:

template <typename Comparable>
struct Foo {
    static bool compare(const Comparable &lhs, const Comparable &rhs) {
        return lhs == rhs;
    }
};

This class template will successfully instantiate the compare function only if the template parameter is an equality-comparable type. It's not called a "bounded type parameter", but it serves the same purpose.

If in C++ you want to treat Comparable as an explicit interface (i.e. a base class) rather than a duck-typed concept, then you can static_assert(is_base_of<Comparable, T>::value, "objects not Comparable");, or whatever.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • 1
    @Eva: you probably weren't following Java when generics were invented, but my perspective was that aside from the stuff that can only be done with runtime introspection, most or all features of generics were invented as tools to achieve in Java things that in C++ were already done with templates. Of course Java has developed its own unique features and idioms from that starting point, since the way that Java went about achieving those aims was different. – Steve Jessop Mar 26 '13 at 11:33
2

no, templates are not a super-set of generics, with C++ templates you have no runtime support at the same level as you have with C# generics, meaning that RTTI in C++ is unable to detect and provide you metadata of templates like Reflection does for generics in C#.

beside this, I like this snippet:

C++ templates use a compile-time model. When a template is used in a C++ program, the effect is as if a sophisticated macro processor had been used.

C# generics are not just a feature of the compiler, but also a feature of the runtime. A generic type such as List maintains its generic-ness (genericity) after it has been compiled. Or, to look at it another way, the substitution that the C++ compiler does at compile time is done at JIT time in the C# generic world.

see here for the full article: How do C# generics compare to C++ templates?

Davide Piras
  • 43,984
  • 10
  • 98
  • 147
  • Java generics are not a runtime feature, but they're still considered generics. – Eva Mar 26 '13 at 10:50
  • 2
    Java generics are different from C# generics, they just share the same name. Don't think that because they called the same thing they are, in fact, the same thing. – Jack Aidley Mar 26 '13 at 10:53
  • @JackAidley They're not exactly the same, but they do have a lot of commonality that makes it sensible for them to be called the same thing. I'm wondering where their commonality diverges enough from templates to make them be called a different thing. – Eva Mar 26 '13 at 10:57
  • @Jack: Java generics (2004) predate C# generics (2005), so if either language owns the term, it'd be Java. – Mr Fooz Mar 26 '13 at 11:25
  • @Eva Yes, they differ significantly. With generics, `Foo` and `Foo` are still the same type (`Foo`). If `Foo` has static members, `Foo` and `Foo` share them. With templates, they're two completely unrelated types once compilation is over; each of `Foo` and `Foo` would have its own copy of static members. – Angew is no longer proud of SO Mar 26 '13 at 11:33
  • 2
    @Angew but the C# thing is also called "generics", and in C# `Foo` and `Foo` get their own static members as well. – harold Mar 26 '13 at 11:36
  • @harold I stand corrected. It seems I don't know enough about C#. – Angew is no longer proud of SO Mar 26 '13 at 11:40
  • 2
    The fact that RTTI does not provide such information does not make much difference, because in general the RTTI in C++ tells you almost nothing about the inspected object's structure. That's a big point, but completely missed. It relates to reflection/introspection features and deficiencies, not about templates/generics. Also, the snippet you cited is somewhat missed, although it is completely true. It is missed because yet again it compares not the templates/generics, but the runtime-introspection features provided by compiler-runtime combo. – quetzalcoatl Mar 26 '13 at 11:48
  • Can you give a practical, concrete example of what C# generic reflection makes easy that is difficult under C++ templates? Ideally one that would not be the same as for a naked class. – Yakk - Adam Nevraumont Mar 26 '13 at 11:52
  • @Yakk: Sure thing: method-invocation by name, instantiating objects at runtime by just knowing their classname. Those basic features greatly hit the possibility of creating plugin-based applications in C++. It is doable, but to reconfigure something you usually have to rebuild the application or module, instead of just changing an .INI file. – quetzalcoatl Mar 26 '13 at 11:55
  • Those look the same as the non template / generic case? What concrete examples are template/generic specific? – Yakk - Adam Nevraumont Mar 26 '13 at 12:22
  • @Yakk: ahh, sorry I've somehow misread your question and ommitted the 'naked class' part. Yes, indeed the examples I provided are for naked classes, hence no relevance to generics themselves. However, you can easily push the same use cases further (although they start becoming much more corner case-y). For example, in C# with normal reflection, you can instantiate an object-by-name. Say string:"Person", puff, you get object of `Person` type. But, with generics you can do it too. Say "Person[]", puff, and you get `IEnumerable`. That **is-a** `IEnumerable` or `IEnumerable` – quetzalcoatl Mar 26 '13 at 13:19
  • @Yakk: The combo of normal reflection, and full runtime type knowledge, and ability to properly **safely** down/up cast dynamically instantiated objects (ever tried to pass an RTTI-enabled MyClass as void* pointer between different modules/compilers?) is the real added feature, but it does not come from the generics themselves. If at some point of time C++ Commitee decides to define proper RTTI handling for templates, than templates will get very close to generics. On the other hand, the Microsoft/ECMA is very unlikely to ever add specializations to generics;) – quetzalcoatl Mar 26 '13 at 13:23
  • @quetzalcoatl Writing type factories/method lookups from string in C++ is a mild annoyance: I've done it enough times. As an aside, how does C# specify that `IEnumerable` is-a `IEnumerable`? `Container` is not a `Container` just because `Person` is a subclass of `Human`, but `Enumerable` is at the least covariant with `Enumerable` in that case. Or does C# just punt and give a runtime error when you try to write to a `Container` that is actually a `Container` with a non-`Person`? – Yakk - Adam Nevraumont Mar 26 '13 at 14:08
  • @Yakk: In C# 'genericity' works in a bit different way for classes and interfaces. In C#, **only on generic interface** you can define "variance" of a type parameter. You cannot specify it on a generic class. Most common example is the `IEnumerable` interface, please note the OUT keyword (there's IN too). This makes `IEnumerable` be a `IEnumerable` but only if Person inherits/implements Human. Therefore every `IEnumerable` is automatically `IEnumerable`. By the words **is-a Type** I mean that such object is castable to that Type via cast, `as/is` operators. – quetzalcoatl Mar 26 '13 at 14:41
  • @Yakk: http://www.codeproject.com/Articles/86419/Variance-in-C-NET-4-0-Covariance-and-Contravarianc Please also note that those are real casts. There are no auto-conversions and no collection wrapping. Runtime knows that Person-inherits-Human, so it allows to plainly cast i.e. List to IEnumerable. This is true for any generic interface that uses variance specifiers, so you can build your code on it too. Combined with interface constraints (`where T: ....`) that makes quite powerful toolset. – quetzalcoatl Mar 26 '13 at 14:44
  • @Yakk: maybe my **is-a** word was a wrong choice. Of course if you do `((IEnumerable)people ).GetType()` you will still get `IEnumerable` response. However I believe you already know what I wanted to say :) – quetzalcoatl Mar 26 '13 at 14:49
0

This is an old thread, and my rep is too low to comment on accepted answer, but I wanted to add:

In addition to explicit specialization, another key difference in C++ templates and C# generics are non-type template parameters used in C++:

template<int bar> class Foo {};

Foo<1> a;
Foo<2> b;

a = b; //error, different types. 

Non-type template parameters can be of any integer types, enumerations, as well as pointers that can be determined at compile time (static storage variables and function pointers). In C++20, they can be of class type too with certain restrictions.

Neither C# nor Java generics can do that.

You can explicitly specialize on non-type parameters as well.

As a side-note, the D programming language uses the term 'template' as nomenclature for generic programming, and its features feel more aligned in spirit to C++ than C#/Java to me at least.

I'm not aware of technical reasons why non-type parameters were left out of C#, but as the language I use more-so than others these days, I miss the feature once in a while.

Jon Wolfe
  • 11
  • 5
-1

I'll confine my answers to C++ templates vs. Java generics.

  1. C++ templates (class templates and functions templates) are mechanisms for implementing compile-time polymorphism, but AFAIK Java generics are run-time mechanisms.
  2. using C++ templates, you can do generic programming and it's actually is totally separate programming style/paradigm, but Java generics are OO style per se. see below:
  3. C++ templates are based on Duck typing, but Java generics are based on Type Erasure. In C++, vector<int>, vector<Shape *>, vector<double> and vector<vector<Matrix>> are 4 distinct types, but in Java Cell<int>, Cell<Integer> Cell<double> and Cell<Matrix> are same type. More precisely, during code generation compiler erases the type at first place. You can check it by following code from the following paper: Vladimir Batov. Java Generics and C++ Templates. C/C++ Users Journal, July 2004.

    public class Cell<E>
    {
       private E elem;
       public Cell(E elem)
       { 
          this.elem = elem;
       }
       public E GetElement()
       { 
          return elem;
       }
       public void SetElement(E elem)
       { 
          this.elem = elem;
       } 
    }
    
    boolean test()
    { 
      Cell<Integer> IntCell(10); 
      Cell<String> StrCell(“Hello”);
      return IntCell.getClass() ==
             StrCell.getClass(); // returns true
    }
    

In short, Java pretends to be generic, while C++ actually is.

Eva
  • 4,397
  • 5
  • 43
  • 65
  • 1
    The question is about the meaning of generics vs templates, not the particular aspects of a single language. – Eva Mar 26 '13 at 12:17
  • @Eva: well maybe you should define what you mean by "generics", because you are lumping things together in different languages that are so different that it makes no sense to talk about them together – newacct Mar 26 '13 at 19:33
  • @newacct I was asking about the definition of generics. The term for C# generics and Java generics is generics, but C++ templates provide much of the same functionality without the same term. I was asking what those have in common that make C# and Java generics, and what differentiates them from templates enough for templates to not be called generics. The lumping was already provided for me. I was just asking why that was the case. – Eva Mar 27 '13 at 01:27
  • @Eva: The name is arbitrary. C++ templates could be called C++ generics if they had named it that way. The name has no meaning. C# and Java generics are very different. They are just called the same. – newacct Mar 27 '13 at 01:40
  • @newacct The [accepted answer](http://stackoverflow.com/a/15636289/830988) and [this comment](http://stackoverflow.com/questions/15634970/what-makes-a-template-different-from-a-generic/15636731?noredirect=1#comment22191152_15634970) explain that the differences are not arbitrary. – Eva Mar 27 '13 at 01:43