Useful D Templates

February 05, 2007 By: erik Category: Geeky 2,396 views

Rate this post:
1 Star2 Stars3 Stars4 Stars5 Stars (2 votes, average: 5.00 out of 5)
Loading...

Recently, I’ve been experimenting with the new D programming language. One thing that’s really amazed me is the power of the templating system. Here are three code-saving templates to help avoid the deadly programming sin of code duplication.

Generic opEquals and opCmp

In D, if you want your objects to be comparable with the ==, < , <=, >, or >= operators, you have to implement opEquals(Object) and opCmp(Object) that take the generic Object type. This is annoying, because it forces you to have to do type checking in every single one of your opEquals and opCmp methods in each class. I have devised a solution.

template GenericEquals(T)
{
  public int opEquals(Object o)
  {
    if(this is o)
      return true;
    T that = cast(T) o;
    if(that is null)  // catches failed casts
      return false;
    else
      return this.opEquals(that);
  }
}

…and…

template GenericCmp(T)
{
  int opCmp(Object o)
  {
    if(this is o)
      return 0;
    T that = cast(T) o;
    if(that is null)  // catches failed casts
      return 1;
    else
      return this.opCmp(that);
  }
}

Then, you can define opEquals and opCmp in your class with the right type of parameter and include the generic forms with a mixin!

class MyClass
{
  private MyField myField;
  
  mixin GenericEquals!(MyClass);
  public int opEquals(MyClass that)
  {
    return this.myField == that.myField;
  }
  
  mixin GenericCmp!(MyClass);
  public int opCmp(MyClass that)
  {
    if(this.myField > that.myField)
      return 1;
    else if(this.myField < that.myField)
      return -1;
    else
      return 0;
  }
}

But look at that opCmp(MyClass) method? Gross! Can’t we remove some of that logic into a template too? Yes, we can! Presenting…

Generic compareFields Template

When you have more than one field that needs to be compared to check for equality and natural ordering of your class, your opCmp method can get pretty ugly and repetitive. For example:

class MyClass
{
  private char[] name;
  private int age;
  
  public int opCmp(MyClass that)
  {
    if(this.name > that.name)
      return 1;
    else if(this.name < that.name)
      return -1;
    else if(this.age > that.age)
      return 1;
    else if(this.age < that.age)
      return -1;
    else
      return 0;
  }
}

I’ve written a compareFields() templated method that will do this for you. But the true beauty of the method is that it is completely type-safe at compile time. It requires an even number of parameters and every pair of parameters have to be of the same type. Behold!

int compareFields(T, R...)(T a, T b, R rest)
{
  if(a > b)
    return 1;
  else if(a < b)
    return -1;
  static if(rest.length)
  {
    static assert(rest.length > 1);
    return compareFields(rest);
  }
  else
    return 0;
}

The method to compare both name and age member variables now becomes:

class MyClass
{
  private char[] name;
  private int age;
  
  public int opCmp(MyClass that)
  {
    return compareFields(this.name, that.name,
                         this.age, that.age);
  }
}

If I leave off a parameter, or accidentally pass “this.name, that.name, this.age, that.name”, it will fail because the second pair of parameters are not of the same type. And again, all this happens at compile time!

This is all made possible by D’s unique variadic templates. Enjoy!

 
  • Pingback: The One With D()

  • Hey, cool! The creator of D, Walter Bright, gave my templates his blessing.

    That’s the geek equivalent of God coming down from the clouds and saying, “Nice work, Noah!”

  • yan

    Cool template =) thanks for sharing this …