April 09, 2010
I am trying to implement a string-like class. I actually have such a class that compiles and works with 2.037; but not I think since 2.041.

I have problems implementing opEquals for this class. A simplified version of the issue is here. This code compiles and works with 2.043, but I have questions below :)

import std.stdio;
import std.algorithm;
import std.conv;

class C
{
    dchar[] chars;

    this(dstring chars)
    {
        // Own characters
        this.chars = chars.dup;
    }

    override bool opEquals(Object o) const
    {
        auto that = cast(C)o;
        return (that !is null) && equal(chars, that.chars);
    }

    bool opEquals(const char[] chars) const
    {
        return equal(this.chars, chars);
    }

    bool opEquals(const wchar[] chars) const
    {
        return equal(this.chars, chars);
    }

    bool opEquals(const dchar[] chars) const
    {
        return equal(this.chars, chars);
    }
}

void main()
{
    // Separate objects
    auto o0 = new C("abcç\U00000ea2"d);
    auto o1 = new C("abcç\U00000ea2"d);

    // Hoping value comparisons
    assert(o0 == o1);
    assert(o0 == "abcç\U00000ea2"c);  // <--- c is required; why?
    assert(o0 == "abcç\U00000ea2"w);
    assert(o0 == "abcç\U00000ea2"d);
}


1) First, should I not even bother with trying to make it so flexible. Perhaps it should not be used with any D string type?


2) Being a reference type, should I not abuse opEquals like that? Perhaps I should overload is_equal() member functions instead?


3) Which opEquals should the 'string' parameter match if I remove the trailing c on the marked line?

Removing that trailing c results in a compiler error:

deneme.d(9780): Error: overloads const bool(const const(char[]) chars) and const bool(const const(dchar[]) chars) both match argument list for opEquals
deneme.d(9780): Error: function deneme.C.opEquals called with argument types:
	((string))
matches both:
	deneme.C.opEquals(const const(char[]) chars)
and:
	deneme.C.opEquals(const const(dchar[]) chars)


4) How would you reduce code duplication above? Implementing opEquals as a template for char[], wchar[], and dchar[] conflicts with opEquals(Object). New function:

    bool opEquals(T)(T chars) const
    {
        return equal(this.chars, chars);
    }

And the error message:

deneme.d(9758): Error: template deneme.C.opEquals(T) conflicts with function deneme.C.opEquals at deneme.d(9752)


5) Then I try a single templated implementation for all comparisons:

    bool opEquals(T)(T chars) const
    {
        static if (is (o : Object))
        {
            auto that = cast(C)o;
            return (that !is null) && equal(chars, that.chars);
        }

        return equal(this.chars, chars);
    }

But it doesn't work, because I can't use the 'override' keyword with it and so it does not override the default implementation for Object. The asserts fail...

Thank you,
Ali