Putting the generic in Generics?
Putting the generic in Generics?
Annoyance 1:
TThing = class
private
FThing: T;
procedure SetThing(const Value: T);
protected
property Thing: T read FThing write SetThing;
public
procedure Configure(const aThing:T = nil); // *
end;
* [dcc32 Error]: E2268 Parameters of this type cannot have default values
Why? It's a class instance pointer, isn't it?
Annoyance 2:
Types are simplified.
Unit 1
TAbstractColumn = class end;
TColumn = class(TAbstractItem) end;
TGridHelper = class(TList>) end;
Unit 2 (uses 1)
TQueryGridHelper = class(TGridHelper) end;
TQueryStrGridHelper = class(TQueryGridHelper);
TQueryDBGridHelper = class(TQueryGridHelper);
note: TDBAdvGrid is a direct descendent of TAdvStringGrid
Unit 3 (uses 1 and 2)
procedure SomeClass.DefineColumns(const aHelper: ???);
If it is defined as
procedure DefineColumns (const Helper: TQueryStrGridHelper);
I get: [dcc32 Error]: E2010 Incompatible types: 'TQueryStrGridHelper' and 'TQueryDBGridHelper' - which is understandable, but how can I specify an argument type for DefineColums which can take both a TQueryStrGridHelper and a TQueryDBGridHelper?
Annoyance 1:
TThing
private
FThing: T;
procedure SetThing(const Value: T);
protected
property Thing: T read FThing write SetThing;
public
procedure Configure(const aThing:T = nil); // *
end;
* [dcc32 Error]: E2268 Parameters of this type cannot have default values
Why? It's a class instance pointer, isn't it?
Annoyance 2:
Types are simplified.
Unit 1
TAbstractColumn = class end;
TColumn
TGridHelper
Unit 2 (uses 1)
TQueryGridHelper
TQueryStrGridHelper = class(TQueryGridHelper
TQueryDBGridHelper = class(TQueryGridHelper
note: TDBAdvGrid is a direct descendent of TAdvStringGrid
Unit 3 (uses 1 and 2)
procedure SomeClass.DefineColumns(const aHelper: ???);
If it is defined as
procedure DefineColumns (const Helper: TQueryStrGridHelper);
I get: [dcc32 Error]: E2010 Incompatible types: 'TQueryStrGridHelper' and 'TQueryDBGridHelper' - which is understandable, but how can I specify an argument type for DefineColums which can take both a TQueryStrGridHelper and a TQueryDBGridHelper?
Re #1, what happens if you write "procedure Configure(const aThing:T = Default(T));"?
ReplyDeleteDavid Millington Doesn't work because the error is not "this particular default value does not work" but "generic type cannot have default value at all"
ReplyDeleteprocedure SomeClass.DefineColumns(const aHelper: TQueryGridHelper)
ReplyDeleteAlso: I smell generics overusage/abuse.
Stefan Glienke We are using these grids by the dozen. They are filled from three different kinds of sources, and we have a lot of scaffolding code that needs to be streamlined. Abuse? Not sure. Overusage - well, it's either that - or repeating the same code in dozens and dozens of places.
ReplyDeleteIt's not the first time I've had a similar problem with Generics. Polymorphism is not trivial with generics if you are unable to have a type-parameterless abstract class as root.
Generics are not to solve polymorphism, that is already solved by OOP. And OOP also already solved only having to writing code once when doing something for a class hierarchy.
ReplyDeleteOOP where the polymorphic variance is based on Generic type T variation makes it difficult to create a root type for the polymorphic hierarchy - because you need methods in the root class which have parameters or results of type T which is not present in the abstract root class.
ReplyDeleteWithout an untyped root class - I can't create procedures that take any descendant of the root class without further type specifiers.
In this case, T can be a specific object class from our hierarchy - or a RecordSet from a query, or a record.
There is one way around it - and that is to pass parameters as typeless and do a cast in the override. Not my favorite way of doing things.
I am talking about putting the grid class as generic parameter which I am sure is unnecessary (I have seen similar code at work where people overused generics and increased the code complexity exponentially).
ReplyDelete