Shortcomings of D-Style Fused Operator Overloading

Ahmet Sait nightmarex1337 at hotmail.com
Fri Jul 7 09:18:38 UTC 2023


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](https://digitalmars.com/articles/b62.html).

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?


More information about the Digitalmars-d mailing list