www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Satisfying inheritence requirements

reply Jason House <jason.james.house gmail.com> writes:
When inheriting from a super class and an interface, I can't seem to get
aliasing to work (to satisfy the interface requirements).  Below is a simple
session demonstrating the problem.  I've tested with dmd 1.018, 1.020, and
2.003.

$ cat test.d
interface Foo{ int bar(); }
class A : Foo{ int bar(){return 1;} }
class B : A, Foo{ alias A.bar bar; }
void main(){}

$ dmd test.d
test.d(3): class test.B interface function Foo.bar is not implemented
Oct 09 2007
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Jason House" wrote
 When inheriting from a super class and an interface, I can't seem to get 
 aliasing to work (to satisfy the interface requirements).  Below is a 
 simple session demonstrating the problem.  I've tested with dmd 1.018, 
 1.020, and 2.003.

 $ cat test.d
 interface Foo{ int bar(); }
 class A : Foo{ int bar(){return 1;} }
 class B : A, Foo{ alias A.bar bar; }
 void main(){}

 $ dmd test.d
 test.d(3): class test.B interface function Foo.bar is not implemented

I'm thinking you have either an incorrectly written example, or you are misunderstanding inheritance. To make this compile, just have B inherit from A. Because A implements Foo, B also implements Foo. As far as I know, an alias cannot satisfy interface requirements, but you don't need it for this. e.g.:
 interface Foo{ int bar(); }
 class A : Foo{ int bar(){return 1;} }
 class B : A { }
 void main(){}

Should compile, and B.bar() should return 1. Now, to give an example where an alias is needed to satisfy interface requirements:
 interface Foo{ int bar(); }
 class A { int baz(){return 1;} }
 class B : A, Foo{ alias A.baz bar;}
 void main(){}

I don't think this will work, and the only way around it is:
 class B : A, Foo{ int bar(){return baz();} }

-Steve
Oct 10 2007
parent reply Jason House <jason.james.house gmail.com> writes:
Steven Schveighoffer Wrote:

 "Jason House" wrote
 When inheriting from a super class and an interface, I can't seem to get 
 aliasing to work (to satisfy the interface requirements).  Below is a 
 simple session demonstrating the problem.  I've tested with dmd 1.018, 
 1.020, and 2.003.

 $ cat test.d
 interface Foo{ int bar(); }
 class A : Foo{ int bar(){return 1;} }
 class B : A, Foo{ alias A.bar bar; }
 void main(){}

 $ dmd test.d
 test.d(3): class test.B interface function Foo.bar is not implemented

I'm thinking you have either an incorrectly written example, or you are misunderstanding inheritance. To make this compile, just have B inherit from A. Because A implements Foo, B also implements Foo.

You're right, I should have had two different interfaces with A and B inheriting from different ones (or simply have B inherit from interface Foo).
 Now, to give an example where an alias is needed to satisfy interface 
 requirements:
 
 interface Foo{ int bar(); }
 class A { int baz(){return 1;} }
 class B : A, Foo{ alias A.baz bar;}
 void main(){}

I don't think this will work, and the only way around it is:
 class B : A, Foo{ int bar(){return baz();} }


That's what I've been doing, but now that -profile is telling me bar is one of the largest time consumers in the program, I'm going back to trying to get aliasing to work (it was suggested on this mailing list in a past thread of the same title). Using the terms from your example, bar is called 10x more than any other function. The baz function is really simple (almost as simple as "return 1"). The total time per call is only 1 tick (microsecond). Maybe it's just a fluke with the profiling, or maybe it really is significant. I wanted to try the alias trick to see if it'd drop it in the overal profiler output.
Oct 10 2007
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Jason House" wrote
 Steven Schveighoffer Wrote:
 Now, to give an example where an alias is needed to satisfy interface
 requirements:

 interface Foo{ int bar(); }
 class A { int baz(){return 1;} }
 class B : A, Foo{ alias A.baz bar;}
 void main(){}

I don't think this will work, and the only way around it is:
 class B : A, Foo{ int bar(){return baz();} }


That's what I've been doing, but now that -profile is telling me bar is one of the largest time consumers in the program, I'm going back to trying to get aliasing to work (it was suggested on this mailing list in a past thread of the same title). Using the terms from your example, bar is called 10x more than any other function. The baz function is really simple (almost as simple as "return 1"). The total time per call is only 1 tick (microsecond). Maybe it's just a fluke with the profiling, or maybe it really is significant. I wanted to try the alias trick to see if it'd drop it in the overal profiler output.

A function that only calls another function and returns that result should at LEAST be optimized to a call/ret instruction pair. A good compiler will optimize it to a jump instruction. If the compiler is clever enough, it will be inlined and you won't even notice that it is calling a different function. I don't think that is your problem. If it's possible, you could post the code or a trimmed down version that has the same problem, and someone may have a good solution for you. -Steve
Oct 10 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Steven Schveighoffer wrote:
 "Jason House" wrote
 Steven Schveighoffer Wrote:
 Now, to give an example where an alias is needed to satisfy interface
 requirements:

 interface Foo{ int bar(); }
 class A { int baz(){return 1;} }
 class B : A, Foo{ alias A.baz bar;}
 void main(){}

 class B : A, Foo{ int bar(){return baz();} }


That's what I've been doing, but now that -profile is telling me bar is one of the largest time consumers in the program, I'm going back to trying to get aliasing to work (it was suggested on this mailing list in a past thread of the same title). Using the terms from your example, bar is called 10x more than any other function. The baz function is really simple (almost as simple as "return 1"). The total time per call is only 1 tick (microsecond). Maybe it's just a fluke with the profiling, or maybe it really is significant. I wanted to try the alias trick to see if it'd drop it in the overal profiler output.

A function that only calls another function and returns that result should at LEAST be optimized to a call/ret instruction pair. A good compiler will optimize it to a jump instruction. If the compiler is clever enough, it will be inlined and you won't even notice that it is calling a different function. I don't think that is your problem. If it's possible, you could post the code or a trimmed down version that has the same problem, and someone may have a good solution for you. -Steve

Did you compile with the -inline flag? --bb
Oct 10 2007
parent reply Jason House <jason.james.house gmail.com> writes:
Bill Baxter Wrote:
 Did you compile with the -inline flag?
 
 --bb

I had not... Only -O. Are there any other good optimization options to use besides -O and -inline? What does -release do?
Oct 10 2007
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Jason House wrote:
 Bill Baxter Wrote:
 Did you compile with the -inline flag?

I had not... Only -O. Are there any other good optimization options to use besides -O and -inline? What does -release do?

'-release' disables asserts and array bounds checks, and removes pre- and post-condition blocks (in{}/out{}) on functions. You could also try marking the function 'final' if it's never overridden. This allows the compiler to bypass the vtable (saving a few instructions per call) if calling through a class reference[1] and may make -inline more effective. [1]: It won't work for interfaces, and struct member functions are implicitly final.
Oct 10 2007
parent Jason House <jason.james.house gmail.com> writes:
Frits van Bommel Wrote:
 '-release' disables asserts and array bounds checks, and removes pre- 
 and post-condition blocks (in{}/out{}) on functions.

strangely, -release makes the program slower. (might be related to tango warning messages that I get when compiling with -release?)
 You could also try marking the function 'final' if it's never 
 overridden. This allows the compiler to bypass the vtable (saving a few 
 instructions per call) if calling through a class reference[1] and may 
 make -inline more effective.

It's true that the way I use interfaces in the code could be replaced with template-based usage instead. I do like how the use of interfaces forces the code that uses them to not cheat and use functions that are not part of the interface. I'm not at the point where this is such a high fraction of my runtime that I'm willing to do the templating trick just yet. I'll definitely keep it in mind though. I'm thinking I could enforce proper interface usage by instantiating the templated objects with the literal interfaces.
 
 
 [1]: It won't work for interfaces, and struct member functions are 
 implicitly final.

Oct 10 2007