Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dart: Delegate the comparison operator of a derived class to comparison operator of base class

Tags:

dart

I want to overload the the comparison operator (==) in Dart to compare structures. Now I'm not sure how to do this for derived classes when I already have overloaded the comparison operator of the base class and want to reuse that.

Assuming I have a a base class like:

class Base
{
  int _a;
  String _b;

  bool operator ==(Base other)
  {
    if (identical(other, this)) return true;
    if (_a != other._a) return false;
    if (_b != other._b) return false;
    return true;
  }
}

Then I declare I derived class that adds additional fields and also want to overload operator==. I only want to compare the additional fields in the derived class and delegate the comparison of Base fields to the Base class. In other programming languages I could do something like Base::operator==(other) or super.equals(other), but in Dart I can't figure out what's the best way to do it.

class Derived extends Base
{
  int _c; // additional field

  bool operator ==(Derived other)
  {
    if (identical(other, this)) return true;        
    if (_c != other._c) return false; // Comparison of new field

    // The following approach gives the compiler error:
    // Equality expression cannot be operand of another equality expression.
    if (!(super.==(other))) return false;

    // The following produces "Unnecessary cast" warnings
    // It also only recursively calls the Derived operator
    if ((this as Base) != (other as Base)) return false;    

    return true;
  }
}

I guess what I could do is:

  • Compare all fields of base class also in the derived class: Is very error prone if base class get's changed and also doesn't work when base and derived are in different packages.
  • Declare an equals function with the same logic as currently operator == in it, call super.equals() to compare the base class and delegate all calls of operator== to the equals function. However it doesn't look too appealing to implement equals and operator ==.

So what's the best or recommended solution for this problem?

like image 737
Matthias247 Avatar asked Oct 20 '13 14:10

Matthias247


2 Answers

Ok, after some further experiments I figured it out on my own. It's simply calling:

super==(other)

I tried it with super.operator==(other) and super.==(other) before, but didn't expect that the simple super==(other) is sufficient.

For the given example above the correct operator is:

bool operator ==(Derived other)
  {
    if (identical(other, this)) return true;
    if (_c != other._c) return false;
    if (!(super==(other))) return false;
    return true;
  }
like image 149
Matthias247 Avatar answered Sep 25 '22 22:09

Matthias247


Seems I am bumping a 5 year old question, but since now we have Dart 2...

the == operator can easily be defined inline.

class Base {
    int a;
    String b;

    bool operator ==(other) => other is Base
          && other.a == a
          && other.b == b;
}

To reuse from a derived class, super == other still seems to be the way.

class Derived extends Base {
    int c;

    bool operator ==(other) => other is Derived
          && super == other
          && other.c == c;
}

Now this being said I discovered a major gotcha, the == operator that is called seems to be that of the left side of the comparision. That is Base == Derived will call Base's == comparision, while Derived == Base will call call Derived's == comparison (and subsequently Base's). This does seem reasonable, but had me scratching my head for a minute.

Ex:

main() {
    Base b = new Base();
    Derived d1 = new Derived();
    Derived d2 = new Derived();

    b.a = 6;
    d1.a = 6;
    d2.a = 6;

    b.b = "Hi";
    d1.b = "Hi";
    d2.b = "Hi";

    d1.c = 1;
    d2.c = 1;

    assert(d1 == d2); // pass
    assert(b == d1);  // PASS!!!
    assert(d1 == b);  // fail
}

(Note: I removed the private _'s from the fields for demonstration purposes.)

like image 43
Rob C Avatar answered Sep 24 '22 22:09

Rob C