View mode: basic / threaded / horizontal-split · Log in · Help
October 09, 2007
Satisfying inheritence requirements
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
October 10, 2007
Re: Satisfying inheritence requirements
"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
October 10, 2007
Re: Satisfying inheritence requirements
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.
October 10, 2007
Re: Satisfying inheritence requirements
"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
October 10, 2007
Re: Satisfying inheritence requirements
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(){}
>>> 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 

Did you compile with the -inline flag?

--bb
October 10, 2007
Re: Satisfying inheritence requirements
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?
October 10, 2007
Re: Satisfying inheritence requirements
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.
October 10, 2007
Re: Satisfying inheritence requirements
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.
Top | Discussion index | About this forum | D home