- THIS IS A CONTINUATION OF THE PREVIOUS POST -
A Generic Inheriting a Generic in a Generic Way - 1
------
Now, back to the problem that started this. I could very well be on the wrong track in how I am approaching my problem.
The problem I had was that I wanted a generic of data_type to inherit a generic of data_type. i.e.:
generic TMyListBase<data_type> = class
Procedure VirtualProc( data : data_type ); virtual; abstract;
Procedure InternalProc; // <-- which uses VirtualProc
end;
generic TMyList<data_type> = class (specialize TMyListBase<data_type>)
.. whatever I need goes here ..
end;
Then, I can make
TIntegerList = specialize TMyList<integer>
TBooleanList = specialize TMyList<boolean>
TStringList = specialize TMyList<string>
etc..
and have them implement their own VirtualProc and I only had to define InternalProc once!
Now, I *do* actually have a working workaround to this problem, but ideally I'd like it to be solved as stated above.
Also, my problem is in fact not wholly mine! I share it with another programmer:
http://forum.lazarus.freepascal.org/index.php?topic=9933.0My solution using interjections follows, with example usage:
----START OF CODE a generic inheriting a generic in a generic way--
{ In this unit we will construct the classes:
TMyListBoolean, TMyListByte, TMyListInteger
TMyListBaseBoolean, TMyListBaseByte, TMyListBaseInteger }
unit TMyLists;
interface
uses
Classes;
type
Interjection GTMyListBase_interface;
start
GTMyListBase = class
Procedure VirtualProc( data : data_type ); virtual; abstract;
Procedure InternalProc;
end;
stop;
Interjection GTMyList_interface;
start
generic GTMyList<data_type> = class (GTMyListBase)
Procedure VirtualProc; override;
end;
stop;
Interjection Interface_Code( TypePtr : pointer );
start
{$extdef 'data_type' := NameThatType(TypePtr)}
{$extdef 'GTMyListBase' := 'TMyListBase' + NameThatType(TypePtr)}
{$extdef 'GTMyList' := 'TMyList' + NameThatType(TypePtr)}
{$Interject GTMyListBase_interface}
{$Interject GTMyList_interface}
{$unextdef 'data_type'}
{$unextdef 'GTMyListBase'}
{$unextdef 'GTMyList'}
stop;
{$Interject Interface_Code( boolean )}
{$Interject Interface_Code( byte )}
{$Interject Interface_Code( integer )}
implementation
Interjection GTMyListBase_implementation( TypePtr : pointer );
start
Procedure GTMyListBase.InternalProc( data : data_type );
begin
writeln( 'InternalProc was just invoked from inside TMyListBase!' );
writeln( 'Now calling VirtualProc with data = ', data );
VirtualProc( data );
end;
stop;
Interjection Implementation_Code( TypePtr : pointer );
start
{$extdef 'data_type' := NameThatType(TypePtr)}
{$extdef 'GTMyListBase' := 'TMyListBase' + NameThatType(TypePtr)}
{$Interject GTMyListBase_implementation}
{$unextdef 'data_type'}
{$unextdef 'GTMyListBase'}
stop;
{$Interject Implementation_Code( boolean )}
{$Interject Implementation_Code( byte )}
{$Interject Implementation_Code( integer )}
Procedure TMyListBoolean.VirtualProc( data : data_type );
begin
writeln( 'VirtualProc was just invoked from inside TMyListBoolean with data = ', data );
end;
Procedure TMyListByte.VirtualProc( data : data_type );
begin
writeln( 'VirtualProc was just invoked from inside TMyListByte with data = ', data );
end;
Procedure TMyListInteger.VirtualProc( data : data_type );
begin
writeln( 'VirtualProc was just invoked from inside TMyListInteger with data = ', data );
end;
var
booleanlist : TMyListBoolean;
bytelist : TMyListByte;
integerlist : TMyListInteger;
begin
booleanlist := TMyListBoolean.Create;
bytelist := TMyListByte.Create;
integerlist := TMyListInteger.Create;
writeln( 'Now calling TMyListBoolean''s InternalProc with data = ', true );
booleanlist.InternalProc( true );
writeln;
writeln( 'Now calling TMyListByte''s InternalProc with data = ', 250 );
bytelist.InternalProc( 250 );
writeln;
writeln( 'Now calling TMyListInteger''s InternalProc with data = ', -10 );
integerlist.InternalProc( -10 );
writeln;
FreeAndNil( booleanlist );
FreeAndNil( bytelist );
FreeAndNil( integerlist );
end.
THE OUTPUT OF THE ABOVE PROGRAM IS:
Now calling TMyListBoolean's InternalProc with data = TRUE
InternalProc was just invoked from inside TMyListBase!
Now calling VirtualProc with data = TRUE
VirtualProc was just invoked from inside TMyListBoolean with data = TRUE
Now calling TMyListByte's InternalProc with data = 250
InternalProc was just invoked from inside TMyListBase!
Now calling VirtualProc with data = 250
VirtualProc was just invoked from inside TMyListByte with data = 250
Now calling TMyListInteger's InternalProc with data = -10
InternalProc was just invoked from inside TMyListBase!
Now calling VirtualProc with data = -10
VirtualProc was just invoked from inside TMyListInteger with data = -10
----END OF CODE a generic inheriting a generic in a generic way----
What are the advantages of interjections over templates?
1) -We can have all required code in one file
2) -Thus, it is more readable
3) -Perhaps we could make the debugger step through the interjections just like we do normal procedures and also convert the code using the macros *on* *the* *fly*! That would be cool!
4) -Also, it would be great if the debugger was able to go to the line of code that is problematic when compiling, and show appropriate identifier names
Problems encountered, disadvantages:
1) -It is not as clean as actually having a generic inherit a generic; maybe the compiler can use interjections and "hide" all of the above so the programmer does not have to bother with the nitty-gritty
2) -It should be possible to use interjections defined outside your unit if the unit is used. In doing so, however, sometimes you may be required to share certain variables between units that you would otherwise not want to.
------
Now, can this be of any help to anyone? I hope so! Personally, I'd be able to use interjections to simplify my work.
Now, I've probably made lots and lots of mistakes above.. so please take it all with a heaping cup of salt (plus I originally wrote most of it at night, couldn't sleep again..).
And if you can tell me how to make a generic class inherit a generic class in a generic way - without interjections - then please tell me, before I write this.
Hope you dream wonderful programs in the future!
IndigoBoy83