2006年06月14日

汝のコンパイラを愛せよ

 まずはこちらをご覧いただきたい――『間違ったコードは間違って見えるようにする』


 アプリケーションハンガリアンはコンパイラの関知しないところにあるので、コンパイルエラーを出してくれない。しかしC#なら、アプリケーションハンガリアンをやめて、型を使う方法がある。

using System;

namespace MyNS
{
struct Int32Derivative<T>
{
private Int32 val;
public static Int32Derivative<T> operator +(Int32Derivative<T> left, Int32 right)
{
return new Int32Derivative<T>(left.val + right);
}
public static Int32Derivative<T> operator -(Int32Derivative<T> left, Int32 right)
{
return new Int32Derivative<T>(left.val - right);
}
public static Int32 operator -(Int32Derivative<T> left, Int32Derivative<T> right)
{
return left.val - right.val;
}
public static Int32Derivative<T> operator *(Int32Derivative<T> left, Int32 right)
{
return new Int32Derivative<T>(left.val * right);
}
public static Int32Derivative<T> operator ++(Int32Derivative<T> left)
{
return new Int32Derivative<T>(left.val++);
}
public static Int32Derivative<T> operator --(Int32Derivative<T> left)
{
return new Int32Derivative<T>(left.val--);
}
public Int32Derivative(Int32 a)
{
val = a;
}
}
}

 型Tはダミーだ。

 Int32Derivativeを使うと、このように書ける。

using System;

namespace MyNS
{
using RowIdx = Int32Derivative<RowIdxStub>;
using ColIdx = Int32Derivative<ColIdxStub>;
class RowIdxStub
{
// nothing
}
class ColIdxStub
{
// nothing
}
class Program
{
static void Main(string[] args)
{
RowIdx ir = new RowIdx(0);
RowIdx ir2 = ir + 10;
int diff = ir - ir2;
ColIdx ic = new ColIdx(200);
ic++;
}
}
}

 RowIdxとColIdxのあいだの演算や型変換がコンパイルエラーになるのはもちろん、RowIdx同士・ColIdx同士の足し算も失敗する。そしてRowIdx同士・ColIdx同士の引き算はちゃんとintを返す。

 なお、私はこの手法を思いついただけで、実際に使ったことはない。あしからず。

Posted by hajime at 2006年06月14日 21:10
Comments