www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Compare two objects

reply Qian Xu <quian.xu stud.tu-ilmenau.de> writes:
Hi All,

I want to test, if two objects are equal. 
The rules are as follows: 
1. When both are null, it should return true. 
2. When one of them is null, it should return false.
3. When both not null, then compare their values (as two strings)

My test code
---------------------------------------------------------------
class Test {
  private int value;
  this(int value) {
    this.value = value;
  }
  public int getValue() {
    return this.value;
  }
  bool opEquals(Test obj) {
    if (obj is null) {
      return this is null;
    }
    return this.getValue() == obj.getValue();
  }
}

procedure test(Test a, Test b) {
  if (a is null && b is null) return true;
  if (a !is null && a == b) return true;
  return false;
}

void main()
{
  Test a;
  Test b = new Test(100);
  assert(test(a, b)); // ok
  assert(a != b); // av error
}
----------------------------------------------------------------

If object at the left side of the != is null, I will get an AV error
immediately.
If I want to compare two objects safely, I have to write my own test(..)
function.
But this is not nice.

Can someone explain, is this a design shortcoming of D-Compiler, or I am
wrong.

Best regards
--Qian Xu
Feb 10 2009
next sibling parent reply grauzone <none example.net> writes:
Qian Xu wrote:
 Hi All,
 
 I want to test, if two objects are equal. 
 The rules are as follows: 
 1. When both are null, it should return true. 
 2. When one of them is null, it should return false.
 3. When both not null, then compare their values (as two strings)
 
 My test code
 ---------------------------------------------------------------
 class Test {
   private int value;
   this(int value) {
     this.value = value;
   }
   public int getValue() {
     return this.value;
   }
   bool opEquals(Test obj) {
     if (obj is null) {
       return this is null;
     }
     return this.getValue() == obj.getValue();
   }
 }
 
 procedure test(Test a, Test b) {
   if (a is null && b is null) return true;
   if (a !is null && a == b) return true;
   return false;
 }
 
 void main()
 {
   Test a;
   Test b = new Test(100);
   assert(test(a, b)); // ok
   assert(a != b); // av error
 }
 ----------------------------------------------------------------
 
 If object at the left side of the != is null, I will get an AV error
 immediately.
 If I want to compare two objects safely, I have to write my own test(..)
 function.
 But this is not nice.
 
 Can someone explain, is this a design shortcoming of D-Compiler, or I am
 wrong.
It's a shortcoming in the design of the == operator. Code like "a==b" will always be compiled to this:
 a.opEquals(b)
If a is null, the call will always cause a segfault. You simply can't call a method on a null object. There are two reasons for this: 1. it will dereference the object's vtable to look up virtual methods and 2. the runtime will try to call the object's invariant, which segfaults too. (Actually, I see an assert with a null check in _d_invariant(). But somehow, gdb usually still shows a segfault in _d_invariant(). Maybe Phobos isn't compiled in debug mode.) The D compiler even has a special rule to disallow compilation of code like "a==null" (yes, because of the null literal). It seems Walter added this, because people were using this code to check if an object is null. Conclusion: == is absolutely useless in your case. Use something else.
 Best regards
 --Qian Xu
 
 
 
Feb 10 2009
parent Qian Xu <quian.xu stud.tu-ilmenau.de> writes:
grauzone wrote:
 
 Conclusion: == is absolutely useless in your case. Use something else.
But you have to write much more, just like my test(..) function does --Qian Xu
Feb 10 2009
prev sibling parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Qian Xu wrote:
 Hi All,
 
 I want to test, if two objects are equal. 
 The rules are as follows: 
 1. When both are null, it should return true. 
 2. When one of them is null, it should return false.
 3. When both not null, then compare their values (as two strings)
((a is b) || (a && a == b)) Note that if a and b are both the same non-null object, opEquals will not be called; it'll just evaluate to true. It's not very nice-looking, but it's the best you can do. Of course, you could put it into a function: ----- bool equals(T)(T a, T b) { return ((a is b) || (a && a == b)); } ----- Note that this may behave strangely for empty arrays: ----- char[] str; equals(str, ""); // returns false ----- But of course, that's what you asked for. 'str' is null and "" isn't...
Feb 10 2009
parent reply Frank Benoit <keinfarbton googlemail.com> writes:
(a && a == b)
is sufficient for his use case. Because he wants the way with the least
amount of typing.
Feb 10 2009
parent Frank Benoit <keinfarbton googlemail.com> writes:
Frank Benoit schrieb:
 (a && a == b)
 is sufficient for his use case. Because he wants the way with the least
 amount of typing.
hm, no :(
Feb 10 2009