I have been playing around with the D Programming Language lately, and I love it. D combines the low-level control of C and modern productivity features like garbage collection, a built in unit-testing framework and – the most recent feature – real closures.
But D is still a young language, and as such a little rough around the edges. It jumps out and bites me every now and then, forcing me to change some of my most common coding habits. Here are a couple of gotchas that made me trip more than once.
What’s the value of the variable after the assignment below?
real a = 5/2;
In D, the answer is 2. The reason for this unintuitive behavior is D’s arithmetic conversion rules which only takes operand types into consideration. A division between two integers result in an integer as well. The desired type, the type of the resulting variable, is disregarded.
To get the desired result we need to convert at least one of the operands to a floating-point number. This can be done in two ways. Either literally:
real a = 5.0/2; // a=>2.5
Or with an explicit cast:
real a = cast(real)5/2; // a=>2.5
Note that you must convert the operand, not the result. So this won’t work:
real a = cast(real)(5/2); // a=>2
The Premature Conversion gotcha is a particularly nasty one. It compiles and runs, which means only testing can reveal this bug.
Testing for identity
I’m a defensive programmer. I like to put assertions whenever I make assumptions in my code. By far, the most common assumption I make, is that an object is assigned. Here’s how I normally do it:
assert(o != null, "o should be assigned!");
In D, this is a big gotcha. The code above works as long as o is not null. If o is unassigned, we’ll get a nasty Access Violation Error. Here’s another example:
SomeObject o = null; if (o == null) // <= Access Violation o = new SomeObject;
The reason is that D supports overloaded operators, in this case the equality operators (== and !=). Unlike Java, D converts the equality operator into a method call without checking for null references. So, internally, the above code gets converted to the following:
SomeObject o = null; if (o.opEquals(null)) o = new SomeObject;
Since o is null, the call to opEquals result in an Access Violation. Instead you should use the is operator to check for identity.
if(o is null) ...
assert(o !is null, ...)
Despite the tripping, I actually like the idea of a separate identity operator. After all, “is a equivalent to b?” is a different question than “are a and b the same object?”. But, as we say in Sweden, It’s difficult to teach old dogs to sit.