Hello,
Michael Van Canneyt schrieb:
For example; MI for interfaces for me is strange (to say the least) because interfaces were introduced to avoid the mess of MI in the first place. So why on earth would you want to introduce it ??
Because MI itself isn't bad, it's often an appropriate representation of
some abstract model. There's only the problem when there are different
implementations for the same method, that's why it is generally avoided. This is multiple _implementation_ inheritance. Commonly considered bad =)
Since interfaces do not have/inherit implementations by definition this
is not an issue, they simply aggregate function *specifications* (no code). This is multiple _interface_ inheritance. Commonly considered good =)
Effectively it cuts down typing involved in creating interface
hierarchies dramatically, or actually enabling some things. Another thing that comes to my mind is that it allows some clever tagging with empty interfaces (without saying anything of importance).
Example (probably not ideal, but I hope mostly self-explaining):
type IInput = interface ... method specifications ... end; IOutput = interface ... method specifications ... end; IInOut = interface(Input, Output) ... method specifications ... end;
IBlockdeviceReaderWriter = interface(IInout, ...) ... method specifications ... end;
IStreamedReaderWriter = interface(IInout, ...) ... method specifications ... end;
TSomeClass = class(<ancestorA>, IBlockdeviceReaderWriter) ... method specs + implementations ... end;
TSomeOtherClass = class(<ancestorB>, IStreamReaderWriter) end;
[...]
- You can use both TSomeClass and TSomeOtherClass in methods using an IInOut now, this includes easy testing that TSomeClass and TSomeOtherClass have the required capabilities by
var instance : either TSomeClass or TSomeOtherClass;
SomeProcessingMethod(x : IInout); and SomeProcessingMethod(x as IInout);
Not
SomeProcessingMethod(x : TObject); and SomeProcessingMethod(x);
and test that x implements both IOut and IIn before using it in the method (or before calling the method, or using overloading in some cases).
Still both implementations retain the flexibility of being allowed to be derived some different ancestors _if needed and appropriate_.
- if you add a subinterface to IInOut you'd have to revise all your code and add this interface to all class specifications... I don't hope you forget one (since the "as" is evaluated at compile time, happy bug hunting).
- tagging of instances with (empty) interfaces and use of existing methods for checking.
type IMammal = interface; IMeatEater = interface; IPlantEater = interface; IEatsEverything = interface(IMeatEater, IPlantEater); IRat = interface(IMammal, IEatsEverything);
Checking an instance for being a rat (implementing IRat) is just a matter of "supports(instance, IRat)", not necessarily "supports(instance, IMammal) and supports(instance, IMeatEater) and supports(instance, IPlantEater)".
In Pascal sets may be used for that. But consider that every one of those interfaces specifies one or more particular methods... (maybe this example is better than the above one after all). There's no way other than dirty tricks(*1) to make sure that the instance implements a method which is called according to the interface type (and actually call it!).
The classes implementing these interface still must implement the methods (*once* for every class hierarchy build). But they don't need to have a common ancestor. (Using decorators you can employ those though).
*1: my best bet would be defining a common abstract class providing all methods in an abstract way, and the successors implementing this one partially. From the design pov this is not a good idea...
I hope this somewhat gives you an idea of the capabilites of this feature.
(Actually COM interfaces can be considered somewhat degenerate in that aspect)
---------------- Btw, also D8 supports it:
http://bdn.borland.com/article/0,1410,29779,00.html
I don't see a reason why there's an ambiguous call error in the example (I think this is due to implementation restrictions/compatibility issues) - after all there is only one implementation for ICombo available.
Btw, D8+ also supports "as" between two interfaces as seen from the example.
Regards, Thomas
_______________________________________________ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal