Basically, we will promote classes that are multiply-inherited into .NET interfaces. To give an example if in Eiffel you have:
class C inherit A B end
then in .NET you might have the following set of classes and interfaces:
class A implements IA class B implements IB class C implements IA and IB interface IA interface IB
This is one way of seeing it, but we could generate it in many different ways. It is important that:
Because of the last point, we decided that we would indeed generate the following set of classes and interfaces:
class A_IMP implements A class B_IMP implements B class C_IMP implements A and B and inherits A_IMP interface B interface C
Note:
Class C_IMP inherits most of its implementation from A_IMP. This is done to
avoid code duplication.
So if in Eiffel you have the following piece of code:
b: B c: C create c b := c
It will translate in C# as:
B b; C c; /* Method 1 */ c = new C_IMP(); b = c; /* Method 2 */ c = EiffelFactory.new_C(); b = c;
Note:
Creation is performed in two different ways. One through the use of a .NET
constructor, and the second one through a factory call. Both will be implemented
in case there is no way to use the .NET constructor mechanism, but we will try
to stick as much as possible on the use of .NET constructor.
Let's suppose we have the following example. In which we do most of what can be seen in an Eiffel library that uses multiple inheritance.
class A feature f is do ... end g (x: X) is do ... end end
class B inherit A rename f as h redefine g end feature g (y: Y) is do ... end end
class C inherit A end
class D inherit B select g end C rename g as C_g select f end end
deferred class F feature f is do end end
class E inherit C undefine f end F end
class X end
class Y inherit X end
This is better described by the following BON diagram:
Let's have a look at what we should generate as an inheritance hierarchy:
The hierarchy is quite complex, but it is required to export the Eiffel multiple inheritance to other languages.
.interface A { f (); g (X x); } .class A_IMP: A { f () {}; g (X x) {}; }
.interface B: A { h (); g (Y y); } .class B_IMP: B, A_IMP { h {} { .override A_IMP::f call A_IMP::f }; g (Y y) {}; private __g (X x) { .override A_IMP::g call B_IMP::g ((Y)x)) } }
.interface C: A .class C_IMP: C, A_IMP
.interface D: B, C { C_g (X x); } .class D_IMP: D, B_IMP { f() {}; // Same implementation as A_IMP::f C_g (X x) {}; // Same implementation as A_IMP::g }
.interface F { f(); } .class F_IMP: F { f() {}; }
.interface E: C, F .class E_IMP: E, C_IMP { f() {}; // Same implementation as F_IMP::f private __f () { .override C_IMP::f throw InvalidCallException; } }