Here's another post in the series, this time it's C++ vs. the D programming language.

Let's talk about templates. If you've ever tried templates in C++ you surely as hell recall the pages and PAGES of compiler errors and seemingly random placement of typename keyword. Trust me, there are EVEN WORSE problems with templates in C++... Consider the following:

struct Foo {
  template<int N>
  void bar() {}

  template<int N>
  struct Bar {};
};

template<typename T>
void f() {
  T foo;
  foo.template bar<0>();         // Line 12
  typename T::template Bar<0> b; // Line 13
}

int main() {
  f<Foo>();
}

This little snippet is pretty simple, but... OH GOD! Lines 12 and 13. What the hell?

Line 12 shows the so-called object.template function<arg>() syntax and it is probably the least known C++ syntax out there. The reason it exists is simple - in this particular corner case the compiler simply... can't... parse... this code. When parsing f() functions definition it can't possibly know that T foo has a templated member bar and confuses the template opening bracket with the less-than operator, so we end up with an unresolved overloaded function type error. That's harsh.

Line 13 contains a similar corner case where we need to use all kinds of messed up syntax just to declare a variable. The typename tells the compiler that we want a type because you know, it won't figure it out on its own. Next, we access with a :: the templated member type Bar instantiated with a 0. The template is there for the same reason it's found on line 12.

Here's the semantically equivalent code in the D programming language:

struct Foo {
  void bar(int N)() {}

  struct Bar(int N) {}
}

void f(T)() {
  T foo;
  foo.bar!0(); // Line 9
  T.Bar!0 b;   // Line 10
}

void main() {
  f!Foo();
}

The analogous lines (9 & 10) will always mean the same and don't require disambiguation with any keywords.

C++' template problem may not seem that serious, but imagine more complicated templates and, oh snap, debugging their code and all the weird stuff that happens when you forget a random =template= keyword somewhere. And I didn't even start ranting about...1

// ...C++11.
template <size_t k, class T, class... Ts>
typename enable_if<k != 0, typename tuple_element<k, tuple<T, Ts...>>::type&>::type // WAT
get(tuple<T, Ts...>& t) {
  tuple<Ts...> & super = t;
  return get<k - 1>(super);
}

To sum it up, D's template syntax is simpler, corner cases don't exist 2 and declarations are cleaner. This is a yet another reason I like D so much.


2016-02-16: Adjusted some links & tags.

  1. The snippet comes from an awesome presentation given by Andrei Alexandrescu on the Going Native 2012 conference a while ago. I didn't get into any details because it's a topic for another rant. Stay tuned.
  2. Don't quote me on that one.