recursive equal, and firstDifference functions

Jonathan M Davis jmdavisProg at gmx.com
Tue Mar 19 12:07:40 PDT 2013


On Tuesday, March 19, 2013 11:12:38 H. S. Teoh wrote:
> On Tue, Mar 19, 2013 at 01:48:43PM -0400, Jonathan M Davis wrote:
> > On Tuesday, March 19, 2013 18:26:16 timotheecour wrote:
> > > > somewhere else, but I don't see a relevant package. Maybe a new
> > > > std.algorithm2 for non-ranges?
> > > > 
> > > > Also, the OT's firstDifference would go there too, and I have a
> > > > recursive (to specified level) toStringRecurse that would
> > > > belong there too.
> > > 
> > > Also, I'd add to that list copyRecurse and some more, that
> > > operate on arbitrary types, not just ranges, so we have:
> > > 
> > > equalRecurse
> > > copyRecurse (deep copy)
> > > toStringRecurse
> > > firstDifference (see OT)
> > > toHashRecurse (should compare equal with a data structure
> > > serialized and then deserialized via a serialization function, eg
> > > std.orange)
> > > 
> > > I'm sure there's more.
> > > 
> > > that seems a starting point for a new package that operates on any
> > > type recursively (not just ranges), no? std.deep?std.recurse? Some
> > > of those could have a depth level compile time parameter that stops
> > > recursion at that level, which would be infinity by default.
> > 
> > And how do you even have the concept of recursion without some sort of
> > range or container to recursively iterate through?
> 
> [...]
> 
> One can iterate over every member of a struct/class and recursively
> invoke equalRecurse on them. Something like this:
> 
> bool recursiveEqual(T)(T a, T b) {
> static if (isAtomic!T) {
> return a == b;
> } else {
> foreach (attr; __traits(getAllMembers, T)) {
> // TBD: need to skip stuff like member
> // functions or internal stuff like
> // compiler-generated attributes, hidden
> // context ptrs, etc.
> 
> alias attr1 = __traits(getMember, a, attr);
> alias attr2 = __traits(getMember, b, attr);
> 
> if (!recursiveEqual(attr, attr2))
> return false;
> }
> }
> return true;
> }

True, but that's completely different from what equal does, and it would be 
very dangerous IMHO. opEquals is supposed to be handling comparing types 
recursively like that. Deciding on your own that a type's member variables 
should be compared with equal instead of == risk doing some nasty things to 
the semantics of the types that you're dealing with. If a type's member 
variables need to be compared with equal, then its opEquals should do that.

equal is for handling the case where you're comparing two arbitrary ranges of 
elements. You don't care what the types of the ranges are. You're comparing 
the elements, not the ranges. You would only need to recursively compare the 
elements with anything other than == if they were ranges, and you wanted to 
ultimately compare the elements of the deepest ranges. == already exists to 
compare the elements themselves recursively.

I'd strongly argue that a function like the one that you just gave is an 
extremely bad idea. It's trying to implement == for a type. Let the type define 
that for itself like it's supposed to.

- jonathan M Davis


More information about the Digitalmars-d-learn mailing list