www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - [help]operator overloading with opEquals in a class

reply zhang <bitworld qq.com> writes:
This code belown can be compiled with DMD 2.050. However, it throws an error
message: 
core.exception.HiddenFuncError: Hidden method called for main.AClass

I'm not sure about whether it is a bug. Thanks for any help.
 


import std.stdio;

class AClass
{
    int data;

// It's wrong
    bool opEquals(AClass a)
    {
        writefln("running here.");
        return data == a.data;
    }

// It works
//    bool opEquals(Object a)
//    {
//        writefln("running here.");
//        return data == (cast(AClass)a).data;
//    }

}


int main(string[] args)
{

    AClass class1 = new AClass();
    AClass class2 = new AClass();

    if(class1 == class2)
        writefln("==");
    else
        writefln("!=");

    return 0;
}

----------
Zhang <bitworld qq.com>

s
Nov 03 2010
next sibling parent Benjamin Thaut <code benjamin-thaut.de> writes:
Am 03.11.2010 13:07, schrieb zhang:
 This code belown can be compiled with DMD 2.050. However, it throws an error
message:
 core.exception.HiddenFuncError: Hidden method called for main.AClass

 I'm not sure about whether it is a bug. Thanks for any help.



 import std.stdio;

 class AClass
 {
      int data;

 // It's wrong
      bool opEquals(AClass a)
      {
          writefln("running here.");
          return data == a.data;
      }

 // It works
 //    bool opEquals(Object a)
 //    {
 //        writefln("running here.");
 //        return data == (cast(AClass)a).data;
 //    }

 }


 int main(string[] args)
 {

      AClass class1 = new AClass();
      AClass class2 = new AClass();

      if(class1 == class2)
          writefln("==");
      else
          writefln("!=");

      return 0;
 }

 ----------
 Zhang<bitworld qq.com>

 s

I'm not shure if it is a bug or not, but to fix it you could add "alias object.opEquals opEquals;" before your first opEquals. Had that already many times, it also happens a lot with opCmp. -- Kind Regards Benjamin Thaut
Nov 03 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 03 Nov 2010 13:57:09 -0400, Benjamin Thaut  
<code benjamin-thaut.de> wrote:

 Am 03.11.2010 13:07, schrieb zhang:
 This code belown can be compiled with DMD 2.050. However, it throws an  
 error message:
 core.exception.HiddenFuncError: Hidden method called for main.AClass

 I'm not sure about whether it is a bug. Thanks for any help.


 I'm not shure if it is a bug or not, but to fix it you could add "alias  
 object.opEquals opEquals;" before your first opEquals. Had that already  
 many times, it also happens a lot with opCmp.

First, it's not a bug, you should only ever override with bool opEquals(Object). Second, using the alias trick does not work for opEquals. x == y *specifically* calls (cast(Object)x).opEquals(cast(Object)y). So if you did that, your override would never be called. -Steve
Nov 03 2010
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday, November 03, 2010 10:57:09 Benjamin Thaut wrote:
 Am 03.11.2010 13:07, schrieb zhang:
 This code belown can be compiled with DMD 2.050. However, it throws an
 error message: core.exception.HiddenFuncError: Hidden method called for
 main.AClass
 
 I'm not sure about whether it is a bug. Thanks for any help.
 
 
 
 import std.stdio;
 
 class AClass
 {
 
      int data;
 
 // It's wrong
 
      bool opEquals(AClass a)
      {
      
          writefln("running here.");
          return data == a.data;
      
      }
 
 // It works
 //    bool opEquals(Object a)
 //    {
 //        writefln("running here.");
 //        return data == (cast(AClass)a).data;
 //    }
 
 }
 
 
 int main(string[] args)
 {
 
      AClass class1 = new AClass();
      AClass class2 = new AClass();
      
      if(class1 == class2)
      
          writefln("==");
      
      else
      
          writefln("!=");
      
      return 0;
 
 }
 
 ----------
 Zhang<bitworld qq.com>
 
 s

I'm not shure if it is a bug or not, but to fix it you could add "alias object.opEquals opEquals;" before your first opEquals. Had that already many times, it also happens a lot with opCmp.

It has to do with function overload sets: http://www.digitalmars.com/d/2.0/function.html Functions in base classes are completely shadowed by those in the derived class as far as overloading goes. Using the alias brings the overload into the overload set for the derived class. However, I would advise against declaring a version of opEquals() or opCmp() that takes anything other than an Object. The way they both work is designed around there being the one overload with takes Object, and generally speaking having function overloads which take a base and derived class is asking for trouble. As soon as you add another derived class on top of it, it's going to choke because it can no longer get an exact match. e.g. void func(A a) {...} void func(B b) {...} class A { ... } class B : A { ... } class C : B { ... } You can't call func with an object of type C without a cast because both the A and B version accept it and neither match C exactly. D's overloading rules are stricter than C++'s, which makes it so that you have a lot fewer cases (possibly none) of a particular overload being called when you expect a different one to be called, but it also makes it so that the compiler doesn't do some of the implicit conversions that you might expect it to. Really, you should just define the one opEquals() and opCmp() and cast the Object inside of it.h If you'll notice, opEquals() already isn't the function that gets called when == or != is used, but rather Objects opEquals() which takes two parameters is, so it already takes care of any issues with the two objects being the same or being null, as well as dealing with transivity and whatnot. opCmp() doesn't do that though, so you could likely still get null values in it. In any case, the design is that you directly override the opEquals() and opCmp() in Object, not that you create ones with new signatures. - Jonathan M Davis - Jonathan M Davis
Nov 03 2010
prev sibling next sibling parent reply =?iso-8859-2?B?VG9tZWsgU293afFza2k=?= <just ask.me> writes:
Dnia 03-11-2010 o 13:07:25 zhang <bitworld qq.com> napisa=B3(a):

 // It works
 //    bool opEquals(Object a)
 //    {
 //        writefln("running here.");
 //        return data =3D=3D (cast(AClass)a).data;
 //    }

It should be: override equals_t opEquals(Object o) { writefln("running here."); if (auto a =3D cast(AClass) o) return data =3D=3D a.data; else return false; } I'm surprised it even compiled without 'override'. BTW, anybody knows what the equals_t bool alias is for? -- = Tomek
Nov 03 2010
parent bearophile <bearophileHUGS lycos.com> writes:
Tomek S:

 I'm surprised it even compiled without 'override'.

It's not obligatory yet: http://d.puremagic.com/issues/show_bug.cgi?id=3836 It's one of the warnings I am waiting to become errors: http://d.puremagic.com/issues/show_bug.cgi?id=4216 Bye, bearophile
Nov 03 2010
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 11/3/10 7:07 AM, zhang wrote:
 This code belown can be compiled with DMD 2.050. However, it throws an error
message:
 core.exception.HiddenFuncError: Hidden method called for main.AClass

 I'm not sure about whether it is a bug. Thanks for any help.

That hidden functions are signaled during run time and not compile time is a misunderstanding between design and implementation. There should not be a HiddenFunc exception and the compiler should just refuse to compile the program. Andrei
Nov 03 2010
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrei:

 That hidden functions are signaled during run time and not compile time 
 is a misunderstanding between design and implementation. There should 
 not be a HiddenFunc exception and the compiler should just refuse to 
 compile the program.

If you compile this program, derived from the OP one: import std.c.stdio: puts; class Foo { int x; bool opEquals(Foo other) { // wrong puts("running here."); return this.x == other.x; } } void main() { auto f1 = new Foo(); auto f2 = new Foo(); puts((f1 == f2) ? "==" : "!="); } With -w, it doesn't compile and gives the error: test.d(3): Error: class test.Foo object.Object.opEquals(Object o) is hidden by Foo That warning just needs to become an error message as soon as possible. See: http://d.puremagic.com/issues/show_bug.cgi?id=4216 It's in my list of about 20 very small changes that I'd like to see ASAP in D2. Bye, bearophile
Nov 03 2010
parent dennis luehring <dl.soluz gmx.net> writes:
 That warning just needs to become an error message as soon as possible. See:
 http://d.puremagic.com/issues/show_bug.cgi?id=4216
 It's in my list of about 20 very small changes that I'd like to see ASAP in D2.

can you please create an small web-page (or blog, or whatever) to save your always (very most of the time) ideas, change request etc. maybe splitted by D2,D3 - small, huge, evil ratings... and keep that up to date - so can refere better and nothing is lost in the huge mass of others posts in this newsgroup
Nov 04 2010
prev sibling parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
On 03/11/2010 20:33, Andrei Alexandrescu wrote:
 On 11/3/10 7:07 AM, zhang wrote:
 This code belown can be compiled with DMD 2.050. However, it throws an
 error message:
 core.exception.HiddenFuncError: Hidden method called for main.AClass

 I'm not sure about whether it is a bug. Thanks for any help.

That hidden functions are signaled during run time and not compile time is a misunderstanding between design and implementation. There should not be a HiddenFunc exception and the compiler should just refuse to compile the program. Andrei

Indeed! Is this part of the spec, or has Walter not agreed to it? -- Bruno Medeiros - Software Engineer
Nov 26 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 11/26/10 9:30 AM, Bruno Medeiros wrote:
 On 03/11/2010 20:33, Andrei Alexandrescu wrote:
 On 11/3/10 7:07 AM, zhang wrote:
 This code belown can be compiled with DMD 2.050. However, it throws an
 error message:
 core.exception.HiddenFuncError: Hidden method called for main.AClass

 I'm not sure about whether it is a bug. Thanks for any help.

That hidden functions are signaled during run time and not compile time is a misunderstanding between design and implementation. There should not be a HiddenFunc exception and the compiler should just refuse to compile the program. Andrei

Indeed! Is this part of the spec, or has Walter not agreed to it?

I think he was worried about the compiler becoming too restrictive. Andrei
Nov 26 2010
parent Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
On 26/11/2010 16:56, Andrei Alexandrescu wrote:
 On 11/26/10 9:30 AM, Bruno Medeiros wrote:
 On 03/11/2010 20:33, Andrei Alexandrescu wrote:
 On 11/3/10 7:07 AM, zhang wrote:
 This code belown can be compiled with DMD 2.050. However, it throws an
 error message:
 core.exception.HiddenFuncError: Hidden method called for main.AClass

 I'm not sure about whether it is a bug. Thanks for any help.

That hidden functions are signaled during run time and not compile time is a misunderstanding between design and implementation. There should not be a HiddenFunc exception and the compiler should just refuse to compile the program. Andrei

Indeed! Is this part of the spec, or has Walter not agreed to it?

I think he was worried about the compiler becoming too restrictive. Andrei

Well... I don't even know how to argue against that. I mean, when would a programmer ever prefer a runtime error instead of a compile-time one in this scenario? It's akin to saying the override keyword should never create a compile-time error, but instead throw a runtime one if the override-marked method doesn't actually override a super method. (note: I know it's not your reasoning, but Walter's) -- Bruno Medeiros - Software Engineer
Nov 29 2010
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday, November 03, 2010 13:27:16 Tomek Sowi=F1ski wrote:
 BTW, anybody knows what the equals_t bool alias is for?

I think that for some reason, opEquals() returned int in D1 instead of bool= , but=20 not having used D1, I'm 100% not sure. If that's the case, then using equal= s_t=20 and having equals_t be int in D1 and bool in D2 makes the code more portabl= e=20 between the two versions. Personally, I always just use bool though. =2D Jonathan M Davis
Nov 03 2010