An idiom for disabling implicit conversions

Don nospam at nospam.com
Fri Mar 19 01:42:03 PDT 2010


I've found a pretty cool idiom for disabling pesky implicit conversion.

This is a situation that I've encountered with BigInt; but I think it's 
a general problem.
I have an "add integer" operation. Let's call it:
void add( x ), where x is a built-in integral type.

If I define add(long x), everything works great -- it can be called with 
x as a byte, ubyte, short, ushort, int, uint, or long.
Well, almost. Unfortunately, it doesn't work for ulong: add(ulong.max) 
will either fail to compile, or get implicitly cast to add(-1)!!

You can fix this by defining add(ulong x) as a special case. Now x can 
be long or ulong, and it works. Great!
Problem is, now if x is an integer, the compiler complains that it's 
ambiguous -- should it call the long or the ulong version? Bummer!

You could solve that by creating int, uint, short, ushort,... functions. 
Eight in total, but seven of them are identical. Massive source code 
duplication. So use a template:

void add(T)(T x)
{
   // everything except ulong
}

void add(T : ulong)(T x)
{
}

Problem solved! Well, not quite. Now the source code duplication is 
gone, but you still have template bloat: there are still 8 functions in 
the executable. Then consider
void evenworse(x, y)
where both x AND y need special treatment if they are ulong. 8*8 = 64 
functions go into the executable, but only 4 of them are different! Ouch.

If only there was a way to disable implicit conversions...

void add()(long x)
{
     assert(x == 7);
}

void add(Tulong)(Tulong x)   if ( is(Tulong == ulong) )
{
     assert(x == 6);
}

void main()
{
     add(7L);
     add(6UL);
     add(7); // Look ma, no conflicts! No bloat!
}

Template constraints are seriously cool.



More information about the Digitalmars-d mailing list