www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 1124] New: inconsistent: "<" calls opCmp(typeof(this) o); but array.sort calls opCmp(Object o)

reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1124

           Summary: inconsistent: "<" calls opCmp(typeof(this) o); but
                    array.sort calls opCmp(Object o)
           Product: D
           Version: 1.010
          Platform: PC
        OS/Version: Linux
            Status: NEW
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: bugzilla digitalmars.com
        ReportedBy: someanon yahoo.com


If a class define both:

opCmp(Object o)
opCmp(typeof(this) o)

"<" calls opCmp(typeof(this) o); but array.sort calls opCmp(Object o)

I think we should always call opCmp(typeof(this) o).
call opCmp(Object o) only if opCmp(typeof(this) o) is not defined.

===================================================================
class A {
public:
  float value;

  this(float v) {value=v;}

  int opCmp(Object o) {
    printf("call opCmp(Object o)\n");
    A a = cast(A)o;  // ugly cast
    return this.value < a.value;
  }

  int opCmp(typeof(this) o) {
    printf("call opCmp(typeof(this) o)\n");
    return this.value < o.value;
  }
}

int main(char[][] args) {
  int i;
  A[3] arr;

  arr[0] = new A(1.0);
  arr[1] = new A(3.0);
  arr[2] = new A(2.0);

  i = arr[0] < arr[1];
  printf("%d\n", i);

  for (i=0; i<3; i++) { printf("%f ", arr[i].value); } printf("\n");
  arr.sort;
  for (i=0; i<3; i++) { printf("%f ", arr[i].value); } printf("\n");

  return 0;
}

==================================================================
$ dmd.exe sortbug.d
g:\project\dmd\bin\..\..\dm\bin\link.exe sortbug,,,user32+kernel32/noi;

$ ./sortbug.exe
call opCmp(typeof(this) o)
0
1.000000 3.000000 2.000000
call opCmp(Object o)
call opCmp(Object o)
call opCmp(Object o)
3.000000 2.000000 1.000000


-- 
Apr 11 2007
parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1124


smjg iname.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |smjg iname.com




------- Comment #1 from smjg iname.com  2007-09-29 07:31 -------
That array.sort calls opCmp(Object) is as documented:

http://www.digitalmars.com/d/1.0/arrays.html
"For the .sort property to work on arrays of class objects, the class
definition must define the function: int opCmp(Object). This is used to
determine the ordering of the class objects. Note that the parameter is of type
Object, not the type of the class."

However, this itself seems to be due to Walter's aversion to implementing such
features as this using templates.

That relational operators call opCmp(typeof(this) o) is a little inaccurate -
actually they call opCmp(typeof(that) o).  But this is sensible.  If both
methods exist, then they would have to be equivalent to make sense, likely by
this idiom:

class Qwert {
    int opCmp(Object o) {
        return opCmp(cast(Qwert) o);
    }

    int opCmp(Qwert q) {
        ...
    }
}

In this case, why take the performance hit of a runtime cast if it's known at
compile time that the RHS is a Qwert?

This becomes even more significant if the class is comparable with more than
one other class, and you need different code to implement each.  Then you'd
need something like

class Qwert {
    int opCmp(Object o) {
        if (cast(Qwert) o) return opCmp(cast(Qwert) o);
        if (cast(Yuiop) o) return opCmp(cast(Yuiop) o);
        assert (false);
    }

    int opCmp(Qwert q) {
        ...
    }

    int opCmp(Yuiop y) {
        ...
    }
}

The compiler won't necessarily inline the opCmp(Object) call.  So cutting out
the middleman really is the right thing.


-- 
Sep 29 2007