recursive equal, and firstDifference functions

Jonathan M Davis jmdavisProg at gmx.com
Tue Mar 19 20:10:24 PDT 2013


On Wednesday, March 20, 2013 01:17:13 Dan wrote:
> This is true, but then my code is by definition not standard.
> However, theoretically, the language writers could. For example,
> any '==' could be lowered to a 'standard' function, probably
> better named 'intancesDeepEqual(a,b)' and that function could use
> reflection to provide equal when not available else call opEquals
> if it is available. Similar with opCmp, dup, idup, ...
> In other words, in the vein of the original poster, why not allow
> all of these nice goodies (equality comparison, opCmp comparison,
> dup) without requiring boilerplate code while still
> honoring/using it when it is provided.

Okay. I'm going to take a second stab at replying to this, because I think 
that I can explain it much better. The standard function that == lowers to is 
opEquals. Nothing else is needed. The way that == works is

integral types, char types, pointers, and bool: bitwise comparison

floating point types: equality which is similar to bitwise comparison but takes 
NaN into account

arrays: The ptr and length attributes are checked, and if the lengths are 
equal but the ptrs are not, then element-wise comparison is used, where each 
element is compared with == (whereas if the lengths are different or if the ptr 
and length attributes are identical, no further comparison is needed).

structs and classes: Their opEquals is used. If a struct or class does not 
define opEquals, then one is generated where each member variable is compared 
in turn with ==. So, they are compared recursively.

They _only_ times that you need you need to worry about defining opEquals are 
when

1. the default comparison is comparing pointers, and you want to compare what 
they point to rather than the pointers themselves.

2. you want equality to mean something other than calling == on each member 
variable (including doing something other than == on a particular member 
variable as might be the case with a member variable which is a range).

The way == is defined is very clean and straightforward. There _are_ bugs which 
complicate things (e.g. http://d.puremagic.com/issues/show_bug.cgi?id=3789 ), 
but those can and will be fixed. The design itself is solid.

It's true that equal is often need for comparing ranges of the same type, but 
that's arguably a defect in the implementations of those ranges. equal is 
specifically designed to compare ranges which are different types but have the 
same element type. == is what's for comparing objects of the same type. But 
most ranges don't currently define opEquals, even when they need it in order 
for it to do a proper comparison. That's arguably something that should be 
fixed, but it's a design issue of ranges, not ==. But if you want to ensure 
that equal is used, you can always use a mixin to define opEquals that way 
(though you actually risk making the comparison less efficient than it would be 
if the ranges themselves defined opEquals).

So, I can see a definite argument that ranges should make sure that they define 
opEquals (which wouldn't negate the general need for equal as that's 
specifically for comparing ranges of different types which have the same element 
type), but there's no need to change how == works. The design is actually very 
clean.

- Jonathan M Davis


More information about the Digitalmars-d-learn mailing list