www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - user defined implicit casts

I have become aware that in D it is possible to create wrapper classes that can
intermingle with primitave types for example:

/**
 * wrappers for all the basic types (and derived types) of D
 * note: these wrappers are mutable
 */
module dragon.math.basictypes;
import dragon.math.numbers;
import std.math;
import std.string;

/// wrapper for byte
class Byte: numeric!(Byte){
	private byte value; /// value of instance
	public:
		this(byte b = 0){ value = b;}	///Constructor
		byte Value() {return value;}	///Returns: value of instance
		void Value(byte b) {value = b;}	///Params: b = new value
		byte opCast() {return value;} /// cast overload
		char[] toString() { return std.string.toString(value);}
		uint toHash() {return abs(value);}

		// binary operator TODO add documentation
		Byte opAdd(Byte b) { return new Byte(value + b.value);}
		Byte opAdd(byte b) { return new Byte(value + b);}
		Byte opSub(Byte b) { return new Byte(value - b.value);}
		Byte opSub(byte b) { return new Byte(value - b);}
		Byte opSub_r(byte b) { return new Byte(b - value);}
		Byte opMul(Byte b) { return new Byte(value * b.value);}
		Byte opMul(byte b) { return new Byte(value * b);}
		Byte opDiv(Byte b) { return new Byte(value / b.value);}
		Byte opDiv(byte b) { return new Byte(value / b);}
		Byte opDiv_r(byte b) {return new Byte(b / value);}
		Byte opMod(Byte b) {return new Byte(value % b.value);}
		Byte opMod(byte b) {return new Byte(value % b);}
		Byte opMod_r(byte b) { return new Byte(b % value);}
		Byte opAnd(Byte b) { return new Byte(value & b.value);}
		Byte opAnd(byte b) { return new Byte(value & b);}
		Byte opOr(Byte b) { return new Byte(value | b.value);}
		Byte opOr(byte b) { return new Byte(value | b);}
		Byte opXor(Byte b) { return new Byte(value ^ b.value);}
		Byte opXor(byte b) { return new Byte(value ^ b);}
		Byte opShl(int i) { return new Byte(value << i);}
		long opShl_r(long l) { return l << value;}
		Byte opShr(int i) {return new Byte(value >> i);}
		long opShr_r(long l) { return l >> value;}
		Byte opUShr(int i) {return new Byte(value >>> i);}
		long opUShr(long l) {return l >>> value;}
		//comparison operators
		int opEquals(Object o) {
			if(o is Byte) {
				Byte b = cast(Byte)o;
				return value == b.value;
			}
			return o == value;
		}
		int opEquals(long l) {
			return l = value;
		}
		int opCmp(Object o) {
			if(o is Byte) {
				Byte b = cast(Byte)o;
				if(value > b.value)return 1;
				if(value < b.value)return -1;
				return 0;
			}
			return o.opCmp(value);
		}
		int opCmp(long l) {
			if(value < l)return -1;
			if(value > l)return 1;
			return 0;
		}
		//assignment operators
		Byte opAssign(byte b) {
			value = b;
			return this;
		}
		Byte opAddAssign(Byte b) {
			value += b.value;
			return this;
		}
		Byte opAddAssign(byte b) {
			value += b;
			return this;
		}
		Byte opSubAssign(Byte b) {
			value -= b.value;
			return this;
		}
		Byte opSubAssign(byte b) {
			value -= b;
			return this;
		}
		Byte opMulAssign(Byte b) {
			value *= b.value;
			return this;
		}
		Byte opMulAssign(byte b) {
			value *= b;
			return this;
		}
		Byte opDivAssign(Byte b) {
			value /= b.value;
			return this;
		}
		Byte opDivAssign(byte b) {
			value /= b;
			return this;
		}
		Byte opModAssign(Byte b) {
			value %= b.value;
			return this;
		}
		Byte opModAssign(byte b) {
			value %= b;
			return this;
		}
		Byte opAndAssign(Byte b) {
			value &= b.value;
			return this;
		}
		Byte opAndAssign(byte b) {
			value &= b;
			return this;
		}
		Byte opOrAssign(Byte b) {
			value |= b.value;
			return this;
		}
		Byte opOrAssign(byte b) {
			value |= b;
			return this;
		}
		Byte opXorAssign(Byte b) {
			value ^= b.value;
			return this;
		}
		Byte opXorAssign(byte b) {
			value ^= b;
			return this;
		}
		Byte opShlAssign(Byte b) {
			value <<= b.value;
			return this;
		}
		Byte opShlAssign(byte b) {
			value <<= b;
			return this;
		}
		Byte opShrAssign(Byte b) {
			value >>= b.value;
			return this;
		}
		Byte opShrAssign(byte b) {
			value >>= b;
			return this;
		}
		Byte opUShrAssign(Byte b) {
			value >>>= b.value;
			return this;
		}
		Byte opUShrAssign(byte b) {
			value >>>= b;
			return this;
		}

		// unary operators TODO add documentation
		Byte opNeg() {return new Byte(-value);}
		Byte opPos() {return new Byte(+value);}
		Byte opCom() {return new Bye(~value);}
		Byte opPostInc() {
			scope temp = value;
			value++;
			return new Byte(temp);
		}
		Byte opPostDec() {
			scope temp = value;
			value--;
			return new Byte(temp);
		}
}

now the problem is a lack of implicit casting for user defined types the Byte
cannot be implicitly cast to byte, int, long etc. even though such a cast would
make sense.  If implicit casting were allowed then a library could be fashioned
with wrapper for all of the basic types and some less basic types such as cint,
iint, fraction, radical, ifraction, cfraction, etc.  

my suggested syntax for overloading implicit casts is:

implicit type1 cast(type2 var);

where type1 is the type casting to and type2 is the type casting from
this syntax would allow non-member functions to be used, so that implicit casts
can be overloaded in specific contexts 
example:
implicit int cast(long var){ return cast(int)var;}
when you know that longs will never exceed the bound of ints
Jul 27 2007