How does D's templated functions implementation differ from generics in C#/Java?

H. S. Teoh hsteoh at quickfur.ath.cx
Fri Aug 7 21:39:44 UTC 2020


On Fri, Aug 07, 2020 at 09:03:47PM +0000, aberba via Digitalmars-d-learn wrote:
> Syntactically they look the same (although D's can do more things) so
> I'm trying to understand how why in D it's called template but in
> languages like C#/Java they're generics.
> 
> I guess I have fair understanding of D's code generation but isn't it
> same as what what is available in those languages too? How are the
> implementation different?

They are *very* different.

Java generics are based on "type erasure", i.e., at the syntactic level,
containers are parametrized with the element types, but at the
implementation level, the element types are merely "erased" and replaced
with Object (a top type of sorts). There is only one container
instantiation, which is shared across all parametrizations.  I don't
know exactly why this approach was chosen, but my guess is, to avoid the
complexities associated with templates (esp. as seen in C++, which was
the prevailing language with type parametrization when Java generics was
being designed), and to avoid template bloat.  But because of how this
implementation works, Java generics are very limited in a lot of ways
that make them feel straitjacketed once you've gotten used to a more
powerful template system like in C++ or especially D. Since the
container does not retain any information about the type parameter, you
cannot perform any type-specific operations on elements (unless you do
runtime introspection -- and I'm not even sure Java lets you do this),
and you cannot make compile-time decisions based on type properties --
because the single container implementation must be able to handle all
type arguments.

D templates do not type-erase, and the generated code retains full
knowledge about the type parameters. Therefore, you can do very powerful
things with them, like Design by Introspection, performing type-specific
operations, generate different code depending on type properties, etc..
Since each template instantiation is distinct, it has the flexibility of
doing completely different things depending on the type arguments,
independently of any other instantiation of the same template.
Furthermore, it can dispatch to a type-erased implementation ala Java --
at your choice; and it can even conditionally do so by inspecting the
properties of the type arguments. IOW, it is a strict superset of Java
generics.

Unfortunately, the power of D templates does come at a cost: if used
carelessly, it can result in a lot of template bloat. Reducing this
bloat often requires delicate code surgery or restriction on some of the
flexibility. (Though IMO, this is not a bad thing -- the user is given
the *choice* to use a type-erased implementation if he so chooses, or
control the template bloat in other ways; in Java, you have no choice
but to live with the limitations of a type-erased generics system. But
then again, Java has always been a bondage-and-discipline kind of
language, so this isn't anything unexpected. People just learn to live
with it.)


T

-- 
Time flies like an arrow. Fruit flies like a banana.


More information about the Digitalmars-d-learn mailing list