A fresh look at comparisons

Janice Caron caron800 at googlemail.com
Thu Apr 17 00:25:29 PDT 2008


On 16/04/2008, Yigal Chripun <yigal100 at gmail.com> wrote:
> OK, I see your point.

Ta. But you see one of my points. I made more than one.


>  If I understood this correctly, the issue is the implicit cast to super.

This particular issue could be dealt with as you suggest, but there
are other issues that it doesn't fix. For example - consider how you
might write an opCmp for complex numbers.

    class Complex
    {
        int opCmp(Object o)
        {
            Complex c = cast(Complex)o;
            if (c is null) return false;

            if (this.im == 0 && c.im == 0)
            {
                if (this.re < c.re) return -1;
                else if (this.re == c.re) return 0;
                else return 1;
            }
            else return ????
        }
    }

The problem is that complex numbers become UNORDERED when the
imaginary part (of either number) becomes non-zero. opCmp() has no way
to express that. Henning Hasemann did suggest making opCmp return an
enum, instead of an int, so that all four possible returns could be
indicated, but again, like you, he's solving one problem at a time.
The whole "fresh look" approach is to solve all of the problems in one
fell swoop. So, this particular problem would be solved in my scheme
with

    class Complex
    {
        is(this < c, unordered)
        {
            if (this.im == 0 && c.im == 0)
            {
                return this.re < c.re;
            }
            else return false;
        }
    }

And there is /yet/ another problem to consider - your "explicit"
approach works just fine for opCmp, but it won't work for opEquals.
The reason is that the default behavior we desire from opCmp is very
different from the default behavior of opEquals. Consider:

    class A { ... }
    class B : A { int x; }

    // Your way
    int opEquals(explicit A a1, explicit A a2);

    B b = new B;
    B c = new C;

    if (b == c)...

Under your scheme, b would not be comparable for equality with c,
since there is no explicit equality test.

By contrast, my scheme would generate a default equality test.
Specifically, b would be considered equal to c if and only if

    (cast(A)b == cast(A)c) && (b.x == c.x)

Of course, in the both schemes, the programmer can always override the
default, by defining an equals comparison for B, but nonetheless, my
scheme gets you a fine default, which is likely to be the right thing
to do much, if not most, of the time.

In other words, I have presented a comprehensive solution which solves
many problems at once, not just a single problem. (Maybe that's why I
have trouble explaining it?)



More information about the Digitalmars-d mailing list