www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - interface and opEquals

reply Oliver <oliver.ruebenkoenig web.de.REMOVE> writes:
Hi everyone,

the following code works and does what it is supposed to do. I am, however,
unsure if this is the "right" way to do it. I read somewhere that opEquals
should take an Object as argument. I can not get the code to work with Object
as argument. Can anyone explain this to be, what am i missing? Thanks to
everyone,

Oliver

------------------------

import std.stdio;

interface Vi {
    void f();
    int opEquals( Vi );
    //int opEquals( Object );
    //int opEquals();
}

class C1 : Vi {
    void f() { writefln( "C1: ", itsInt ); }
    this( int i ) { this.itsInt = i; }
    int opEquals( Vi o ) { 
        C1 test = cast(C1)o;
        return test && this.itsInt == test.itsInt;
    }   
    //int opEquals( C1 test ) { return this.itsInt == test.itsInt; }
private:
    int itsInt;
}

int main() {
    assert( 1 == 1.0 );
    Vi myInt1 = new C1(1);
    Vi myInt2 = new C1(1);
    myInt1.f();
    assert( cast(C1)myInt1 == cast(C1)myInt2 );
    assert( myInt1 == myInt2 );
    return 0;
}
Nov 04 2007
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Oliver" wrote
 Hi everyone,

 the following code works and does what it is supposed to do. I am, 
 however, unsure if this is the "right" way to do it. I read somewhere that 
 opEquals should take an Object as argument. I can not get the code to work 
 with Object as argument. Can anyone explain this to be, what am i missing? 
 Thanks to everyone,

 Oliver

 ------------------------

 import std.stdio;

 interface Vi {
    void f();
    int opEquals( Vi );
    //int opEquals( Object );
    //int opEquals();
 }

 class C1 : Vi {
    void f() { writefln( "C1: ", itsInt ); }
    this( int i ) { this.itsInt = i; }
    int opEquals( Vi o ) {
        C1 test = cast(C1)o;
        return test && this.itsInt == test.itsInt;
    }
    //int opEquals( C1 test ) { return this.itsInt == test.itsInt; }
 private:
    int itsInt;
 }

 int main() {
    assert( 1 == 1.0 );
    Vi myInt1 = new C1(1);
    Vi myInt2 = new C1(1);
    myInt1.f();
    assert( cast(C1)myInt1 == cast(C1)myInt2 );
    assert( myInt1 == myInt2 );
    return 0;
 }

You should use Object as the argument. The reason is simple. If you do not use Object, then the base opEquals function is not overridden. When you use Vi as your argument, you start a new method that is overridden only by derivatives of Vi. Your example isn't a good way to demonstrate why this is bad, but imagine if Vi had a base interface... Having said that, you do not need opEquals to be defined as a method in your interface, because Object already defines it. All classes derived from Object will have a valid opEquals. Perhaps this is why it was not working for you. I think this code would work: import std.stdio; interface Vi { void f(); //int opEquals( Vi ); // ** commented out //int opEquals( Object ); //int opEquals(); } class C1 : Vi { void f() { writefln( "C1: ", itsInt ); } this( int i ) { this.itsInt = i; } int opEquals( Object o ) { // ** changed to Object C1 test = cast(C1)o; return test && this.itsInt == test.itsInt; } //int opEquals( C1 test ) { return this.itsInt == test.itsInt; } private: int itsInt; } int main() { assert( 1 == 1.0 ); Vi myInt1 = new C1(1); Vi myInt2 = new C1(1); myInt1.f(); assert( cast(C1)myInt1 == cast(C1)myInt2 ); assert( myInt1 == myInt2 ); return 0; } -Steve
Nov 05 2007
parent reply Oliver <oliver.ruebenkoenig BLUBweb.de> writes:
Steven Schveighoffer Wrote:


Steve,

thank you for looking into this.

 You should use Object as the argument.  The reason is simple.  If you do not 
 use Object, then the base opEquals function is not overridden.  When you use 
 Vi as your argument, you start a new method that is overridden only by 
 derivatives of Vi. 

That puts it very clearly.
 Your example isn't a good way to demonstrate why this is 
 bad, but imagine if Vi had a base interface...

Unfortunately, I do not understand this. Could you explain a little more, or tell me were i could read up on this?
 Having said that, you do not need opEquals to be defined as a method in your 
 interface, because Object already defines it.  All classes derived from 
 Object will have a valid opEquals.  Perhaps this is why it was not working 
 for you.

 I think this code would work:
 

The second assert fails. And that is the one i would like to work. I have the impression that it does not work because opEquals does not know what to do with Vi objects. Then i tried to have opEquals( Object ) in the interface and wanted opEquals ( C1 test ) in the C1 class. But that did not work either. Which kind of makes sense. hm, i do not really understand this. Any ideas? Thanks, Oliver
 import std.stdio;
 
 interface Vi {
     void f();
     //int opEquals( Vi );  // ** commented out
     //int opEquals( Object );
     //int opEquals();
 }
 
 class C1 : Vi {
     void f() { writefln( "C1: ", itsInt ); }
     this( int i ) { this.itsInt = i; }
     int opEquals( Object o ) { // ** changed to Object
         C1 test = cast(C1)o;
         return test && this.itsInt == test.itsInt;
     }
     //int opEquals( C1 test ) { return this.itsInt == test.itsInt; }
 private:
     int itsInt;
 }
 
 int main() {
     assert( 1 == 1.0 );
     Vi myInt1 = new C1(1);
     Vi myInt2 = new C1(1);
     myInt1.f();
     assert( cast(C1)myInt1 == cast(C1)myInt2 );
     assert( myInt1 == myInt2 );
     return 0;
 }
 
 -Steve 
 
 

Nov 06 2007
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Oliver" wrote
 Steven Schveighoffer Wrote:


 Steve,

 thank you for looking into this.

No problem :)
 Your example isn't a good way to demonstrate why this is
 bad, but imagine if Vi had a base interface...

Unfortunately, I do not understand this. Could you explain a little more, or tell me were i could read up on this?

Here is a better example: import std.stdio; class A { int opEquals(A o) { writefln("A"); return 0; } } class B : A { int opEquals(B o) { writefln("B"); return 0; } } void main() { A x = new B; A y = new B; x == y; } This prints "A". The reason you want to use Object is because the method will override the base class' interface. If you don't do this, you are starting a new method, and comparing two base class objects will result in the comparison NOT calling your method.
 Having said that, you do not need opEquals to be defined as a method in 
 your
 interface, because Object already defines it.  All classes derived from
 Object will have a valid opEquals.  Perhaps this is why it was not 
 working
 for you.

 I think this code would work:

The second assert fails. And that is the one i would like to work. I have the impression that it does not work because opEquals does not know what to do with Vi objects. Then i tried to have opEquals( Object ) in the interface and wanted opEquals ( C1 test ) in the C1 class. But that did not work either. Which kind of makes sense. hm, i do not really understand this. Any ideas?

Hm... I was not aware that interfaces did not have a base interface, or could not be implicitly cast to Object. This makes sense because if you had a base interface that called out opCmp or opEquals, it would not allow Object to fulfill that requirement, and therefore you would be required to always implement those two functions in the class that implements the interface. I can't figure out how you could have the identified two lines below call the same method. Perhaps this is by design? interface I { ... } class C : I { ... } ... I c1 = new C; I c2 = new C; // how can you implement C and I such that the following 2 lines // call the same method? c1 == c2; cast(Object)c1 == cast(Object)c2; For now, my recommendation would be to cast the interfaces to Object before comparing (i.e. second line above). Casting to Object should always work because an interface should always be able to transform into an Object, since the implementation is always a class. It's ugly, but it should work the way you want. Any D gurus have the answer to this? -Steve
Nov 06 2007
parent Oliver <oliver.ruebenkoenig BLUBweb.de> writes:
Steven Schveighoffer Wrote:


 
 Any D gurus have the answer to this?
 
 -Steve 
 
 

Thanks, Steve. I found the following thread: http://www.digitalmars.com/d/archives/digitalmars/D/Object_and_interface_compatibility_48235.html but of course, I'd be very interested to learn if there is another, cleaner, way that casting to Object. Oliver
Nov 07 2007