Original in Russian: http://programmingmindstream.blogspot.ru/2015/07/todo_36.html
Interfaces are usually small, self-sufficient and self-consistent.
A “good”, well-developed interface has 3 to 5 methods that are not derived from each other .
However, there are “monsters” like IStream, IStorage and IDataObject in which interface methods are EXPLICITELY derived from the others by default.
IDataObject is a perfect example since it has GetData and GetDataHere as well as EnumFormatEtc and GetCanonicalFormatEtc .
There are also small interfaces with methods derived from the other methods by default in it.
For example:
It is obvious that EQ can be derived from S and Len methods.
But, “as usual”, the “poor fellows” are forced to implement such “default methods”.
Again and again, one by one, they make systematic errors.
What can be done to it?
Naturally, we can develop a “bundle” of default implementations as global methods and pin the developers down to call these methods.
We can simplly remove the EQ methods from the interface and replace them with a “bundle” of default methods.
But!
Sometimes even OUTSIDE interfaces can be implemented in the code.
Sometimes it is also CONVENIENT to have default redefinable implementation.
So what is to do?
Well, we may add a tick to the model at the interface method “default implementation”.
Next, we add a mixin to code-generation process to the interface with such ticks, for example, a tick at ICString.EQ.
In this case, we get a mixin in code-generation:
Let our TCString class implement (in the model) the ICString interface.
As a result, we have the code:
We may also get the TCString1:
As for me, this idea is interesting, I’ve been looking for it for a long time.
We may move on and add a tree-option “tick” - abstract/virtual/final.
The options:
abstract - we do default implementation.
virtual - we do virtual default implementation.
final - we do final (static) implementation.
+Victor Morozov
+Mikhail Kostitsyn
+Nikolay Zverev
References:
About patterns and mixins
My own implementation of IUnknown and reference counting. And mixins
Briefly. Much about “mixins and patterns” (in Russian)
Once again about “mixins”, now seriously (in Russian)
Languages with mixins possible one way or another (in Russian)
Why UML (in Russian)
I guess it’ll be ready by tomorrow.
Though it is not simple. There are some pitfalls.
If we copy interface methods to te mixin, these methods are implemented in descendants.
As parasites.
If we do not copy them, it is not clear how to show them.
As an option, we can add an “extra cycle” like %o or %O.
Still, how can we find out if “the method has been implemented”?
Should we move it to the PureMixIn?
Actually, it is SIMPLE - we should not implement methods with a tick AT ALL.
Interfaces are usually small, self-sufficient and self-consistent.
A “good”, well-developed interface has 3 to 5 methods that are not derived from each other .
However, there are “monsters” like IStream, IStorage and IDataObject in which interface methods are EXPLICITELY derived from the others by default.
IDataObject is a perfect example since it has GetData and GetDataHere as well as EnumFormatEtc and GetCanonicalFormatEtc .
There are also small interfaces with methods derived from the other methods by default in it.
For example:
type ICString = interaface function S: PChar; function Len: Integer; function EQ(const anOther: ICString): Boolean; end;//ICString
It is obvious that EQ can be derived from S and Len methods.
But, “as usual”, the “poor fellows” are forced to implement such “default methods”.
Again and again, one by one, they make systematic errors.
What can be done to it?
Naturally, we can develop a “bundle” of default implementations as global methods and pin the developers down to call these methods.
We can simplly remove the EQ methods from the interface and replace them with a “bundle” of default methods.
But!
Sometimes even OUTSIDE interfaces can be implemented in the code.
Sometimes it is also CONVENIENT to have default redefinable implementation.
So what is to do?
Well, we may add a tick to the model at the interface method “default implementation”.
Next, we add a mixin to code-generation process to the interface with such ticks, for example, a tick at ICString.EQ.
In this case, we get a mixin in code-generation:
type _CString_ = class(_CString_Parent_) protected function EQ(const anOther: ICString): Boolean; virtual; end;//_CString_ ... function _CString_.EQ(const anOther: ICString): Boolean; begin // - default implementation here end;
Let our TCString class implement (in the model) the ICString interface.
As a result, we have the code:
type _CString_Parent_ = TInterfacedObject; {$Include CString.imp.pas} TCString = class(_CString_, ICString) protected function S: PChar; function Len: Integer; //function EQ(const anOther: ICString): Boolean; // - implemented before, in _CString_ end;//TCString
We may also get the TCString1:
type _CString_Parent_ = TInterfacedObject; {$Include CString.imp.pas} TCString1 = class(_CString_, ICString) protected function S: PChar; function Len: Integer; function EQ(const anOther: ICString): Boolean; override; // - default implementation overriden here end;//TCString1
As for me, this idea is interesting, I’ve been looking for it for a long time.
We may move on and add a tree-option “tick” - abstract/virtual/final.
The options:
abstract - we do default implementation.
virtual - we do virtual default implementation.
final - we do final (static) implementation.
+Victor Morozov
+Mikhail Kostitsyn
+Nikolay Zverev
References:
About patterns and mixins
My own implementation of IUnknown and reference counting. And mixins
Briefly. Much about “mixins and patterns” (in Russian)
Once again about “mixins”, now seriously (in Russian)
Languages with mixins possible one way or another (in Russian)
Why UML (in Russian)
I guess it’ll be ready by tomorrow.
Though it is not simple. There are some pitfalls.
If we copy interface methods to te mixin, these methods are implemented in descendants.
As parasites.
If we do not copy them, it is not clear how to show them.
As an option, we can add an “extra cycle” like %o or %O.
Still, how can we find out if “the method has been implemented”?
Should we move it to the PureMixIn?
Actually, it is SIMPLE - we should not implement methods with a tick AT ALL.