Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are these objects not equal by default in D?

Take a look at this simple class I'm building as the base to store the results of string matching algorithms:

/** Match of a single pattern in full to a single text. */
class Match {
    uint Tpos;

    this(in uint Tpos) { this.Tpos = Tpos; }

    override string toString() {
        return text("Match: Text@",Tpos);
    }
}

Here's where things get weird:

auto m1 = new Match(1), m2 = new Match(1);
writeln(m1.toHash());
writeln(m2.toHash());
writeln(m1 == m2);

prints

4464528
4464512
false

I see no reason why these two objects should not be considered equal by default. I suppose I could write a custom toHash() and opEquals() function, but that seems like overkill. According to Andrei Alexandrescu's book on the D programming language (great book!), "By default, the hash is computed by using the bitwise representation of the object." Any ideas out there?

like image 724
denine99 Avatar asked Aug 23 '12 19:08

denine99


People also ask

Why is an Object not equal to an Object?

Objects are not compared by value: two objects are not equal even if they have the same properties and values. This is true of arrays too: even if they have the same values in the same order. Objects are sometimes called reference types to distinguish them from JavaScript's primitive types.

How do you know if an Object is equal?

The equals() method of the Object class compare the equality of two objects. The two objects will be equal if they share the same memory address. Syntax: public boolean equals(Object obj)

Why use .equals instead of == Java?

We can use == operators for reference comparison (address comparison) and . equals() method for content comparison. In simple words, == checks if both objects point to the same memory location whereas . equals() evaluates to the comparison of values in the objects.

How can you tell if two objects are similar?

To determine if two objects are not identical Set up a Boolean expression to test the two objects. In your testing expression, use the IsNot operator with the two objects as operands. IsNot returns True if the objects do not point to the same class instance.


Video Answer


2 Answers

From the source code (dmd2/src/druntime/src/object_.d):

class Object
{
/* snip */
    /**
     * Compute hash function for Object.
     */
    hash_t toHash() @trusted nothrow
    {   
        // BUG: this prevents a compacting GC from working, needs to be fixed
        return cast(hash_t)cast(void*)this;
    }
/* snip */
    /**
     * Returns !=0 if this object does have the same contents as obj.
     */
    equals_t opEquals(Object o)
    {
        return this is o;
    }
}

So the answer is simply that's the way the code is written - they do an identity check rather than a content check. Why is it this way? I don't really know, but my guess is it was simple to write originally and works well enough that nobody has bothered to come back to it and change it.

On the newsgroup, there's been some discussion of removing these functions from Object entirely, so if you want == on your classes, you'll have to implement something. But the time it takes for newsgroup talk to become action when it comes to things like this is usually pretty long. And they might change their minds.

The best way of using class equality currently and probably in the foreseeable future is to write your own opEquals method in the class.

like image 142
Adam D. Ruppe Avatar answered Sep 20 '22 04:09

Adam D. Ruppe


You have to implement toHash on your own, since Object.toHash depends on the address. If I remember correctly it's just a return cast(hash_t)cast(void*)this.

EDIT: Yes, I remember correctly: https://github.com/D-Programming-Language/druntime/blob/master/src/object_.d#L88

like image 29
dav1d Avatar answered Sep 19 '22 04:09

dav1d