For the past few weeks I've been working on a simple compiler for my grad project, and I was trying to make use of operator overloading in some of my types named Interval and Constant.
Interval supposed to be a type that supports all kinds of arithmetic operations with another Interval which would be used for implementing Value Range Propagation.
Now to the operator overloading part. As I was trying to implement the Interval type, I realized an interesting issue. The way operator overloading works in D is with a unified opCmp()
method that returns -1, 0 or 1 depending on the inequality, and a < b
gets lowered to a.opCmp(b) < 0
. However, implementing inequality correctly for intervals requires us to know the exact operator used.
Let's define two intervals x and y:
{x ∈ ℝ │ a ≤ x ≤ b}
{y ∈ ℝ │ c ≤ y ≤ d}
And the inequality operators:
x < y = ⎧ 1 if b < c
⎨
⎩ 0 otherwise
x ≤ y = ⎧ 1 if b ≤ c
⎨
⎩ 0 otherwise
x > y = ⎧ 1 if a > d
⎨
⎩ 0 otherwise
x ≥ y = ⎧ 1 if a ≥ d
⎨
⎩ 0 otherwise
Exercise: Write an opCmp()
method that implements the rules above for struct Interval { int lower, upper; }
. (Hint: It's not possible.)
I didn't fully implement or used this Interval type I was cooking because I was running out of time for the project, so I opted for something simpler which is to just do constant folding, hence the Constant type. Constant is basically a tagged union like bool|integer|real
, and it doesn't have the fuzzy ordering issues like in the Interval type above.
For Constant, I wanted to implement all unary operators, one of which is logical not !
. The only way to do this in D is by writing a bool opCast(T:bool)
, except I don't want to return a bool! I want to return another Constant that represents the logical inverse of what the current Constant contains, and be able write this:
Constant c2 = !c1; // Lowered to !c1.opCast!bool
As you can guess, returning a Constant from opCast()
instead of bool
results in this error message:
Error: cannot implicitly convert expression c1.opCast()
of type Constant
to bool
Now you might be thinking, I could just define a bunch of regular functions such as logicalNot()
, lowerOrEquals()
etc. and you would be right (which is what I ended up doing anyway). I guess the point here is that the way D merges these operators to reduce potential bugs actually end up making certain things inexpressible naturally.
So what do you guys think? Would you say distinct operators are better?