Bug 323 – Error: need opCmp for class Bar

Status
RESOLVED
Resolution
WONTFIX
Severity
normal
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
x86
OS
Linux
Creation time
2006-09-03T14:13:00Z
Last change time
2015-06-09T01:31:18Z
Assigned to
bugzilla
Creator
someanon

Comments

Comment #0 by someanon — 2006-09-03T14:13:58Z
I think this use to work; now on Linux dmd.166, it reports: Error: need opCmp for class Bar ============================================ template Valuable(T) { protected: float m_value = 0.0; public: float value() {return m_value;} void value(float v) {m_value=v;} int opCmp(T other) { int r; if (value < other.value) {r = -1;} else if (value > other.value) {r = 1;} return r; } } class Foo { } class Bar : Foo { mixin Valuable!(Bar); // defined opCmp to compare Bar public: this(float v) { m_value = v; } } int main(char[][] args) { Bar[3] bars; for (int i = 0; i < 3; i++) { bars[i] = new Bar(i); } bars.sort; return 0; } ============================================
Comment #1 by someanon — 2006-09-03T14:25:52Z
Same problem on WindowsXP: Error: need opCmp for class Bar
Comment #2 by someanon — 2006-09-03T16:48:22Z
Two more questions: 1) this is reported at compile time, but errors out at run-time. Maybe the compiler does see the opCmp, but other things goes wrong. 2) Before I isolate the problem, in my real program: on Linux, it builds and errors out at run-time. But on WinXP, I have a link time error: "Unexpected OPTLINK Termination at EIP=0044C37B". Not sure if it's related to this opCmp issue.
Comment #3 by someanon — 2006-09-03T16:50:01Z
Sorry, typo: 1) this is reported at compile time ... should be: 1) this is NOT reported at compile time ...
Comment #4 by thomas-dloop — 2006-09-07T03:45:18Z
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 [email protected] schrieb am 2006-09-03: > http://d.puremagic.com/issues/show_bug.cgi?id=323 > I think this use to work; now on Linux dmd.166, it reports: http://www.digitalmars.com/d/changelog.html#new0163 # # Object.opCmp now throws an error. Should override it # if used. Breaks existing code. # > Error: need opCmp for class Bar > <snip> > int opCmp(T other) { > int r; > > if (value < other.value) {r = -1;} > else if (value > other.value) {r = 1;} > > return r; > } The cause is a nasty result of D's function inheritance and overriding. http://www.digitalmars.com/d/function.html # # A functions in a derived class with the same name and parameter types # as a function in a base class overrides that function. # Thus "int T.opCmp(T other)" dosen't override "int Object.opCmp(Object o)" ... Should do the trick: # # int opCmp(Object o){ # T t = cast(T) o; # if(t is null){ # return super.opCmp(o); # }else{ # return opCmp(t); # } # } # # int opCmp(T other) { # int r; # # if (value < other.value) {r = -1;} # else if (value > other.value) {r = 1;} # # return r; # } # Thomas -----BEGIN PGP SIGNATURE----- iD8DBQFE/+hrLK5blCcjpWoRAn19AJ4xroQQhMNn1DkxLCAafdrzXw2UswCeNZfA 2eWscmpgVCkItONOreZGRmo= =UXBJ -----END PGP SIGNATURE-----
Comment #5 by sean — 2006-09-07T10:20:34Z
Since D's associative arrays use opCmp to resolve collisions, any class that has opEquals defined should probably have opCmp defined also. The old default implementation of Object.opCmp in Phobos was not compatible with compacting GCs so it was replaced with a version that throws an exception on use. However, there is a default implementation that actually works and is compatible with compacting GCs: int opCmp(Object o) { return this !is o; } Compare to opEquals: int opEquals(Object o) { return this is o; } The opCmp function above forces the binary tree chaining mechanism into a linked-list, and equivalence is resolved by pointer equality rather than some ordering mechanism. It won't be as fast as an ordering implementation of opCall for the degenerate case but it has the benefit of being immune to object movement. If a default implementation of opEquals is to remain in Phobos then I suggest adopting the default opCmp implementation above as well.
Comment #6 by sean — 2006-09-07T13:30:18Z
xs0 wrote: > Sean Kelly wrote: >> Since D's associative arrays use opCmp to resolve collisions, any >> class that has opEquals defined should probably have opCmp defined >> also. The old default implementation of Object.opCmp in Phobos was >> not compatible with compacting GCs so it was replaced with a version >> that throws an exception on use. However, there is a default >> implementation that actually works and is compatible with compacting GCs: >> >> int opCmp(Object o) >> { >> return this !is o; >> } > > That's not a really good solution, as no usable ordering is defined (a>b > and b>a will always be true whenever a !is b). While it may work for > (degenerate) insertion into a binary tree, it's (imho) worse than > throwing an exception in practically all other cases. For example, a > quick sort will not only run really slow in O(n^2) time but also produce > an unsorted result without any indication of error. Ah good point. So any ideas? Personally, I'd be happy if the default AA used a linked-list for chaining and opEquals for comparison so this wasn't an issue, but that seems a foregone conclusion. I'm mostly concerned about providing default behavior that makes sense for the common case. The problem I've run into is that I have objects which need to be used as keys in an AA but are not inherently sortable.
Comment #7 by bruno.do.medeiros+deebugz — 2006-09-11T20:20:17Z
========================================================================== The cause is a nasty result of D's function inheritance and overriding. http://www.digitalmars.com/d/function.html # # A functions in a derived class with the same name and parameter types # as a function in a base class overrides that function. # Thus "int T.opCmp(T other)" dosen't override "int Object.opCmp(Object o)" ... Should do the trick: # # int opCmp(Object o){ # T t = cast(T) o; # if(t is null){ # return super.opCmp(o); # }else{ # return opCmp(t); # } # } # # int opCmp(T other) { # int r; # # if (value < other.value) {r = -1;} # else if (value > other.value) {r = 1;} # # return r; # } # ========================================================================== This is realy ugly. For these special method (.dup, .opCmp, .equals), Why can't we have coveriant parameters, or even anchored types as in eiffel? http://www.pi.informatik.tu-darmstadt.de/inf1/eiff-ref/chap12.htm So we can write more clean code: class Dog : Animal { Dog dup() {...} int opCmp(Dog d) {...} int opEquals(Dog d) {...} } Instead of casting Object around?
Comment #8 by bugzilla — 2008-06-25T02:57:40Z
Covariant function parameters make it very difficult to do overloading - should it be an overload, or an override?
Comment #9 by bugzilla — 2008-06-25T03:18:53Z
I don't think Sean's default opCmp should be used, because it will hide errors where one has not declared an overriding opCmp correctly. I think it is best to leave the throwing one as the default.