July 08, 2013
On Tuesday, July 09, 2013 00:35:32 Ugbar Ikenaki wrote:
> Here's one more question:
> 
> Before I knew that opEquals existed, I tried overloading the equality expressions (== and !=) in opBinary using the code below. It worked. Why would the overloaded opBinary version get called if the equality expressions are held in opEquals? I'm just interested in knowing how dmd chooses where to take an expression from if it lies in multiple places (e.g. == in opEquals and opBinary), even if what I did was just add the == operator to opBinary. (Is that what I did there?)
> 
>         override bool opBinary( string op ) ( Rect r ) if( op ==
> "==" ) {
> 		//Check if rectangle coordinates are equal
> 		if( left == r.left && right == r.right && top == r.top &&
> bottom == r.bottom ) {
> 			return true;
> 		} else {
> 			return false;
> 		}
> 	}
> 
> 
> Thanks!

I don't believe that that will ever work. If you want to overload == and !=, use opEquals. opBinary isn't used for that. Look at http://dlang.org/operatoroverloading.html if you want to see which function to use to overload for each operator.

- Jonathan M Davis
July 08, 2013
On Tue, Jul 09, 2013 at 12:35:32AM +0200, Ugbar Ikenaki wrote:
> Here's one more question:
> 
> Before I knew that opEquals existed, I tried overloading the equality expressions (== and !=) in opBinary using the code below. It worked. Why would the overloaded opBinary version get called if the equality expressions are held in opEquals?
[...]

I doubt opBinary was actually called. Probably what happened was that == defaulted to the built-in implementation of opEquals, which simply performs a bitwise comparison of the struct/class, and it just so happened that it was close to (or the same) as what you intended.

Basically, when you write x==y, the compiler looks for opEquals and opCmp. If opEquals is found, then it's rewritten as x.opEquals(y); otherwise, if opCmp is found, it's rewritten as x.opCmp(y)==0. If neither are found, then the compiler generates a default implementation of opEquals, which basically does a bitwise comparison of x and y.


T

-- 
Arise, you prisoners of Windows
Arise, you slaves of Redmond, Wash,
The day and hour soon are coming
When all the IT folks say "Gosh!"
It isn't from a clever lawsuit
That Windowsland will finally fall,
But thousands writing open source code
Like mice who nibble through a wall.
-- The Linux-nationale by Greg Baker
July 08, 2013
On Monday, July 08, 2013 16:38:16 H. S. Teoh wrote:
> On Tue, Jul 09, 2013 at 12:35:32AM +0200, Ugbar Ikenaki wrote:
> > Here's one more question:
> > 
> > Before I knew that opEquals existed, I tried overloading the equality expressions (== and !=) in opBinary using the code below. It worked. Why would the overloaded opBinary version get called if the equality expressions are held in opEquals?
> 
> [...]
> 
> I doubt opBinary was actually called. Probably what happened was that == defaulted to the built-in implementation of opEquals, which simply performs a bitwise comparison of the struct/class, and it just so happened that it was close to (or the same) as what you intended.
> 
> Basically, when you write x==y, the compiler looks for opEquals and opCmp. If opEquals is found, then it's rewritten as x.opEquals(y); otherwise, if opCmp is found, it's rewritten as x.opCmp(y)==0. If neither are found, then the compiler generates a default implementation of opEquals, which basically does a bitwise comparison of x and y.

Actually, what it's supposed to do isn't necessarily a bitwise comparison. It's supposed to do a recursive comparison of all of the members, where it calls == on each of the members. If a bitwise comparison will do that, then it may end up as a bitwise comparison for efficiency reasons, but it's not necessarily a bitwise comparison. It used to be that it was doing a bitwise comparison when it wasn't supposed to, but that was fixed fairly recently (though I don't recall if that fix has been released yet).

Basically, there's no reason to overload opEquals unless you have a member which you don't want to compare with == (e.g. pointers).

- Jonathan M Davis
July 08, 2013
On Monday, July 08, 2013 16:48:05 Jonathan M Davis wrote:
> On Monday, July 08, 2013 16:38:16 H. S. Teoh wrote:
> > On Tue, Jul 09, 2013 at 12:35:32AM +0200, Ugbar Ikenaki wrote:
> > > Here's one more question:
> > > 
> > > Before I knew that opEquals existed, I tried overloading the equality expressions (== and !=) in opBinary using the code below. It worked. Why would the overloaded opBinary version get called if the equality expressions are held in opEquals?
> > 
> > [...]
> > 
> > I doubt opBinary was actually called. Probably what happened was that == defaulted to the built-in implementation of opEquals, which simply performs a bitwise comparison of the struct/class, and it just so happened that it was close to (or the same) as what you intended.
> > 
> > Basically, when you write x==y, the compiler looks for opEquals and opCmp. If opEquals is found, then it's rewritten as x.opEquals(y); otherwise, if opCmp is found, it's rewritten as x.opCmp(y)==0. If neither are found, then the compiler generates a default implementation of opEquals, which basically does a bitwise comparison of x and y.
> 
> Actually, what it's supposed to do isn't necessarily a bitwise comparison. It's supposed to do a recursive comparison of all of the members, where it calls == on each of the members. If a bitwise comparison will do that, then it may end up as a bitwise comparison for efficiency reasons, but it's not necessarily a bitwise comparison. It used to be that it was doing a bitwise comparison when it wasn't supposed to, but that was fixed fairly recently (though I don't recall if that fix has been released yet).
> 
> Basically, there's no reason to overload opEquals unless you have a member which you don't want to compare with == (e.g. pointers).

I should point out though (in case someone misunderstands) is that that applies specifically to structs. You always have to overload opEquals on classes if you want == to work properly (since Object's opEquals does a comparison of the references rather than the objects).

- Jonathan M Davis
July 08, 2013
On Mon, Jul 08, 2013 at 04:48:05PM -0700, Jonathan M Davis wrote:
> On Monday, July 08, 2013 16:38:16 H. S. Teoh wrote:
[...]
> > Basically, when you write x==y, the compiler looks for opEquals and opCmp. If opEquals is found, then it's rewritten as x.opEquals(y); otherwise, if opCmp is found, it's rewritten as x.opCmp(y)==0. If neither are found, then the compiler generates a default implementation of opEquals, which basically does a bitwise comparison of x and y.
> 
> Actually, what it's supposed to do isn't necessarily a bitwise comparison.  It's supposed to do a recursive comparison of all of the members, where it calls == on each of the members. If a bitwise comparison will do that, then it may end up as a bitwise comparison for efficiency reasons, but it's not necessarily a bitwise comparison. It used to be that it was doing a bitwise comparison when it wasn't supposed to, but that was fixed fairly recently (though I don't recall if that fix has been released yet).
> 
> Basically, there's no reason to overload opEquals unless you have a member which you don't want to compare with == (e.g. pointers).
[...]

Unfortunately, this isn't true for opCmp. If you don't define opCmp, the typeinfo of the struct will have a compare function that basically does bitwise comparison. Proof:

	struct S {
		int[] data;
	}
	void main() {
		auto s = S([1,2,3]);
		auto t = S([1,2,3]);
		auto u = S([1,2,4]);

		assert(s == t);
		assert(s != u);
		assert(typeid(s).compare(&s, &t) == 0); // FAILS
		assert(typeid(s).compare(&s, &u) != 0);
	}

Should this be filed as a DMD bug?


T

-- 
A computer doesn't mind if its programs are put to purposes that don't match their names. -- D. Knuth
July 09, 2013
On Monday, July 08, 2013 16:58:03 H. S. Teoh wrote:
> On Mon, Jul 08, 2013 at 04:48:05PM -0700, Jonathan M Davis wrote:
> > On Monday, July 08, 2013 16:38:16 H. S. Teoh wrote:
> [...]
> 
> > > Basically, when you write x==y, the compiler looks for opEquals and opCmp. If opEquals is found, then it's rewritten as x.opEquals(y); otherwise, if opCmp is found, it's rewritten as x.opCmp(y)==0. If neither are found, then the compiler generates a default implementation of opEquals, which basically does a bitwise comparison of x and y.
> > 
> > Actually, what it's supposed to do isn't necessarily a bitwise comparison.  It's supposed to do a recursive comparison of all of the members, where it calls == on each of the members. If a bitwise comparison will do that, then it may end up as a bitwise comparison for efficiency reasons, but it's not necessarily a bitwise comparison. It used to be that it was doing a bitwise comparison when it wasn't supposed to, but that was fixed fairly recently (though I don't recall if that fix has been released yet).
> > 
> > Basically, there's no reason to overload opEquals unless you have a member which you don't want to compare with == (e.g. pointers).
> 
> [...]
> 
> Unfortunately, this isn't true for opCmp. If you don't define opCmp, the typeinfo of the struct will have a compare function that basically does bitwise comparison. Proof:
> 
> 	struct S {
> 		int[] data;
> 	}
> 	void main() {
> 		auto s = S([1,2,3]);
> 		auto t = S([1,2,3]);
> 		auto u = S([1,2,4]);
> 
> 		assert(s == t);
> 		assert(s != u);
> 		assert(typeid(s).compare(&s, &t) == 0); // FAILS
> 		assert(typeid(s).compare(&s, &u) != 0);
> 	}
> 
> Should this be filed as a DMD bug?

Yes. opCmp's behavior should definitely match opEquals' behavior.

- Jonathan M Davis
July 09, 2013
On Mon, Jul 08, 2013 at 05:09:14PM -0700, Jonathan M Davis wrote:
> On Monday, July 08, 2013 16:58:03 H. S. Teoh wrote:
> > On Mon, Jul 08, 2013 at 04:48:05PM -0700, Jonathan M Davis wrote:
> > > On Monday, July 08, 2013 16:38:16 H. S. Teoh wrote:
> > [...]
> > 
> > > > Basically, when you write x==y, the compiler looks for opEquals and opCmp. If opEquals is found, then it's rewritten as x.opEquals(y); otherwise, if opCmp is found, it's rewritten as x.opCmp(y)==0. If neither are found, then the compiler generates a default implementation of opEquals, which basically does a bitwise comparison of x and y.
> > > 
> > > Actually, what it's supposed to do isn't necessarily a bitwise comparison.  It's supposed to do a recursive comparison of all of the members, where it calls == on each of the members. If a bitwise comparison will do that, then it may end up as a bitwise comparison for efficiency reasons, but it's not necessarily a bitwise comparison.  It used to be that it was doing a bitwise comparison when it wasn't supposed to, but that was fixed fairly recently (though I don't recall if that fix has been released yet).
> > > 
> > > Basically, there's no reason to overload opEquals unless you have a member which you don't want to compare with == (e.g. pointers).
> > 
> > [...]
> > 
> > Unfortunately, this isn't true for opCmp. If you don't define opCmp, the typeinfo of the struct will have a compare function that basically does bitwise comparison. Proof:
> > 
> > 	struct S {
> > 		int[] data;
> > 	}
> > 	void main() {
> > 		auto s = S([1,2,3]);
> > 		auto t = S([1,2,3]);
> > 		auto u = S([1,2,4]);
> > 
> > 		assert(s == t);
> > 		assert(s != u);
> > 		assert(typeid(s).compare(&s, &t) == 0); // FAILS
> > 		assert(typeid(s).compare(&s, &u) != 0);
> > 	}
> > 
> > Should this be filed as a DMD bug?
> 
> Yes. opCmp's behavior should definitely match opEquals' behavior.
[...]

http://d.puremagic.com/issues/show_bug.cgi?id=10588


T

-- 
MSDOS = MicroSoft's Denial Of Service
1 2
Next ›   Last »