www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - D1/D2: How to check if a method has been overridden

reply klickverbot <see klickverbot.at> writes:
Hello all,

as some of you might know, I have started working on a D module for SWIG 
quite some time ago. In the meantime, the project is almost ready for 
inclusion in SWIG trunk as a full-fledged language module supporting 
D1/Tango and D2/Phobos.

However, there is one major blocker left: I need to check if a method 
has been overridden for this in a potential subclass (obviously at 
runtime), as illustrated below.

---
class A {
   void foo( float a ) {}
   void foo( int a ) {}

   final void bar() {
     // Determine whether this.foo( 1 ) and this.foo( 1f ) really refer
     // to A.foo( float ) and A.foo( int ) or if they point to a subclass
     // implementation – how?
   }
}

class B : A {
   override void foo( float a ) {}
}

class C : A {
   override void foo( int a ) {}
}

class D : B {
   override void foo( int a ) {}
}
---

Until DMD 1.047, I have used a piece of code shown in 
http://d.puremagic.com/issues/show_bug.cgi?id=4835, but the casts in 
there are no longer enough for DMD to determine which overload is being 
referred to.

Now, please tell me that there _is_ a way to do this (D1 and D2, but I 
don't mind if have to generate different code for the both)…
Sep 07 2010
next sibling parent reply Mafi <mafi example.org> writes:
Am 07.09.2010 23:00, schrieb klickverbot:
 Hello all,

 as some of you might know, I have started working on a D module for SWIG
 quite some time ago. In the meantime, the project is almost ready for
 inclusion in SWIG trunk as a full-fledged language module supporting
 D1/Tango and D2/Phobos.

 However, there is one major blocker left: I need to check if a method
 has been overridden for this in a potential subclass (obviously at
 runtime), as illustrated below.

 ---
 class A {
 void foo( float a ) {}
 void foo( int a ) {}

 final void bar() {
 // Determine whether this.foo( 1 ) and this.foo( 1f ) really refer
 // to A.foo( float ) and A.foo( int ) or if they point to a subclass
 // implementation – how?
 }
 }

 class B : A {
 override void foo( float a ) {}
 }

 class C : A {
 override void foo( int a ) {}
 }

 class D : B {
 override void foo( int a ) {}
 }
 ---

 Until DMD 1.047, I have used a piece of code shown in
 http://d.puremagic.com/issues/show_bug.cgi?id=4835, but the casts in
 there are no longer enough for DMD to determine which overload is being
 referred to.

 Now, please tell me that there _is_ a way to do this (D1 and D2, but I
 don't mind if have to generate different code for the both)…

Hi, couldn't you just check if a delegate's funcptr is the same as the real funcptr: &this.foo == &foo I'm not sure if the right isn't an shortcut for the left and it could get weird with strange linking but if D really want's to be a system's language then this should work. Mafi
Sep 07 2010
parent klickverbot <see klickverbot.at> writes:
On 9/7/10 11:07 PM, Mafi wrote:
 I'm not sure if the right isn't an shortcut for the left […]

Unfortunately, the right indeed is a shortcut for the left – the lookup is performed using the vtbl. Furthermore, this would not solve my problem with overloaded functions.
Sep 07 2010
prev sibling next sibling parent reply dsimcha <dsimcha yahoo.com> writes:
One way to test for overriding at runtime is to compare the function pointer of
a
delegate obtained at runtime to the function pointer obtained from the compile
time type.

Here's a simplified example:

import std.stdio;

class A {
    void fun() {}
}

class B : A {
    override void fun() {}
}

void main() {
    auto a = new A;
    auto b = new B;

    auto aDel = &a.fun;
    auto bDel = &b.fun;

    writeln(&A.fun is aDel.funcptr);  // True:  fun is not overridden
    writeln(&A.fun is bDel.funcptr);  // False:  fun is overridden
}
Sep 07 2010
parent reply klickverbot <see klickverbot.at> writes:
On 9/7/10 11:12 PM, dsimcha wrote:
 One way to test for overriding at runtime is to compare the function pointer
of a
 delegate obtained at runtime to the function pointer obtained from the compile
 time type.

That's basically the same idea I were already using, but have you tried implementing it for overloaded functions? I have not gotten this to work since there is seemingly no way to do &a.foo then.
Sep 07 2010
parent reply dsimcha <dsimcha yahoo.com> writes:
== Quote from klickverbot (see klickverbot.at)'s article
 On 9/7/10 11:12 PM, dsimcha wrote:
 One way to test for overriding at runtime is to compare the function pointer
of a
 delegate obtained at runtime to the function pointer obtained from the compile
 time type.

implementing it for overloaded functions? I have not gotten this to work since there is seemingly no way to do &a.foo then.

All you need to do is provide an explicit type for the delegate: class A { void fun(uint num) {} void fun(float num) {} } void main() { auto a = new A; void delegate(float) funDel = &a.fun; }
Sep 07 2010
parent reply klickverbot <see klickverbot.at> writes:
Putting the overloading issue aside for a moment, how would you 
implement it inside a member function of a (which is required for 
various reasons?

The following does *not* work, because &A.foo also performs a vtbl 
lookup when put inside A…

---
class A {
     void foo() {}
     void bar() {
        auto thisDg = &this.foo;
        writeln(&A.foo is thisDg.funcptr);
     }
}
---

Besides, it also returns a delegate because of this, which is why the 
code does not even compile, but that would be worked around easily.
Sep 07 2010
parent Jason House <jason.james.house gmail.com> writes:
That looks like something that should go into bugzilla.

klickverbot Wrote:

 Putting the overloading issue aside for a moment, how would you 
 implement it inside a member function of a (which is required for 
 various reasons?
 
 The following does *not* work, because &A.foo also performs a vtbl 
 lookup when put inside A…
 
 ---
 class A {
      void foo() {}
      void bar() {
         auto thisDg = &this.foo;
         writeln(&A.foo is thisDg.funcptr);
      }
 }
 ---
 
 Besides, it also returns a delegate because of this, which is why the 
 code does not even compile, but that would be worked around easily.

Sep 07 2010
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
klickverbot:

 class A {
    void foo( float a ) {}
    void foo( int a ) {}
 
    final void bar() {
      // Determine whether this.foo( 1 ) and this.foo( 1f ) really refer
      // to A.foo( float ) and A.foo( int ) or if they point to a subclass
      // implementation – how?
    }
 }
 
 class B : A {
    override void foo( float a ) {}
 }
 
 class C : A {
    override void foo( int a ) {}
 }
 
 class D : B {
    override void foo( int a ) {}
 }

Have you tried to compile that code with -w? See also: http://d.puremagic.com/issues/show_bug.cgi?id=4216 Bye, bearophile
Sep 07 2010
parent reply klickverbot <see klickverbot.at> writes:
On 9/7/10 11:31 PM, bearophile wrote:
 Have you tried to compile that code with -w?
 See also:
 http://d.puremagic.com/issues/show_bug.cgi?id=4216

 Bye,
 bearophile

Well, I guess I should have wrote the following instead: --- class A { void foo( float a ) {} void foo( int a ) {} final void bar() { // Determine whether this.foo( 1 ) and this.foo( 1f ) really refer // to A.foo( float ) and A.foo( int ) or if they point to a subclass // implementation – how? } } class B : A { alias A.foo foo; override void foo( float a ) {} } class C : A { alias A.foo foo; override void foo( int a ) {} } class D : B { alias B.foo foo; override void foo( int a ) {} } ---
Sep 07 2010
next sibling parent klickverbot <see klickverbot.at> writes:
s/have wrote/have written/
Sep 07 2010
prev sibling parent reply Max Samukha <spambox d-coding.com> writes:
On 09/08/2010 12:33 AM, klickverbot wrote:

 Well, I guess I should have wrote the following instead:

You can avoid messing with vtable: class A { void foo( float a ) {} void foo( int a ) {} // hack to get the static address of an overload private static Fn funcAddr(Fn, alias fn)() { return cast(Fn)&fn; } private bool isOverriden(Dg, alias fn)() { Dg dg = &foo; // check if the static and dynamic addresses match return dg.funcptr != funcAddr!(typeof(dg.funcptr), fn); } final void bar() { writefln("%:", this.classinfo); if (isOverriden!(void delegate(float), foo)) writefln(" foo(float) is overriden"); if (isOverriden!(void delegate(int), foo)) writefln(" foo(int) is overriden"); } } class B : A { alias A.foo foo; override void foo( float a ) {} } class C : A { alias A.foo foo; override void foo( int a ) {} } class D : B { alias B.foo foo; override void foo( int a ) {} } void main() { auto a = new A; a.bar(); a = new B; a.bar(); a = new C; a.bar(); a = new D; a.bar(); } No guarantees at all as you never know whether you are dealing with a bug or feature.
Sep 08 2010
next sibling parent klickverbot <see klickverbot.at> writes:
Hm, strange, this is more or less the same solution I was using up to 
DMD 1.047, but it seems to work on DMD 2.048 too – I'll investigate why…

Thanks a lot, anyway.
Sep 08 2010
prev sibling parent reply klickverbot <see klickverbot.at> writes:
Thanks a lot, Max, for some reason this works, while my own, very 
similar solution doesn't.

Unfortunately, however, this exposes yet another DMD bug: 
http://d.puremagic.com/issues/show_bug.cgi?id=4860.
Sep 13 2010
parent Max Samukha <spambox d-coding.com> writes:
On 09/13/2010 05:56 PM, klickverbot wrote:
 Thanks a lot, Max, for some reason this works, while my own, very
 similar solution doesn't.

In old times &ClassName.foo used to give you exactly what you would expect - the static address of foo. That was extremely useful but "unsafe" because the actual type of the function differed from the type of the function pointer. Things changed at some point and nobody knows whether it is a regression or by design because this feature has never been specified.
 Unfortunately, however, this exposes yet another DMD bug:
 http://d.puremagic.com/issues/show_bug.cgi?id=4860.

A bad one.
Sep 13 2010
prev sibling parent reply Kagamin <spam here.lot> writes:
klickverbot Wrote:

 Now, please tell me that there _is_ a way to do this (D1 and D2, but I 
 don't mind if have to generate different code for the both)…

Isn't this info available through classinfo?
Sep 07 2010
next sibling parent reply klickverbot <see klickverbot.at> writes:
On 9/8/10 8:25 AM, Kagamin wrote:
 Isn't this info available through classinfo?

How exactly would you look this up using classinfo? Maybe it's the lack of documentation, but I didn't see a way to achieve that with Classinfo and friends…
Sep 08 2010
parent Kagamin <spam here.lot> writes:
klickverbot Wrote:

 On 9/8/10 8:25 AM, Kagamin wrote:
 Isn't this info available through classinfo?

How exactly would you look this up using classinfo? Maybe it's the lack of documentation, but I didn't see a way to achieve that with Classinfo and friends…

MemberInfo_function has fp member.
Sep 08 2010
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2010-09-08 08:25, Kagamin wrote:
 klickverbot Wrote:

 Now, please tell me that there _is_ a way to do this (D1 and D2, but I
 don't mind if have to generate different code for the both)…

Isn't this info available through classinfo?

In D2 there is a way to get all the members of a class, including methods. But it doesn't currently work due to some bugs. -- /Jacob Carlborg
Sep 08 2010