Thread overview
Satisfying inheritence requirements
Oct 09, 2007
Jason House
Oct 10, 2007
Jason House
Oct 10, 2007
Bill Baxter
Oct 10, 2007
Jason House
Oct 10, 2007
Frits van Bommel
Oct 10, 2007
Jason House
October 09, 2007
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
"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
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
"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
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
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
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
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.