www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Overloading opEquals

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
Apr 09 2010