I have the following class definition
TBase<T> = class
public
class var Inst: T;
class function GetClone: T;
end;
And I want to check if the class var Inst is assigned.
class function TBase<T>.GetClone: T;
begin
if TBase<T>.Inst = nil then //- error here. Trying with Assigned(TBase<T>.Inst) is also nor recognized.
TBase<T>.Inst := TBase<T>.Create;
end;
How can I check if my class variable is assigned?
You need to constraint the generic parameter in order to check for nil. For example:
TBase<T: class> = class //...
That way T must be TObject or any descendant of it, so you can check for nil.
Without the constraint T can be integer or any other value type that doesn't support nil.
TServiceData = class
strict private
FPriority: Integer;
...
public
property Priority: Integer read FPriority write FPriority;
...
end;
TMonthData = class
strict private
function GetServiceData(AIdx: Integer): TServiceData;
public
...
property ServiceData: TServiceData read GetlstServiceData; // incompatible types - Why?
end;
Sorry. Typing error. Original
property ServiceData: TServiceData read GetServiceData;
Because you do not have argument in the property.
property ServiceData: TServiceData read GetlstServiceData;
See - the GetlstServiceData here can have no arguments because Delphi has nowhere to take them from its only available information source at compile type - the very property ServiceData: TServiceData declaration.
You should either add the argument to the property or to remove it from the function.
TMonthData = class
strict private
function GetValue0Args(): TServiceData;
function GetValue1Arg(const AIdx: Integer): TServiceData;
function GetValue2Args(const AIdx: Integer; const Flavour: string): TServiceData;
public
...
property Data0Args: TServiceData read GetValue0Args;
property Data1Arg[ SlotNumber: integer ]: TServiceData read GetValue1Arg;
property Data2Args[ SNum: integer; Recipient: string ]: TServiceData read GetValue2Args;
end;
See so called "array properties": http://docwiki.embarcadero.com/RADStudio/Seattle/en/Properties#Array_Properties
Though "array properties" are not actually arrays. The term was poorly selected: arrays would never take complex entities like strings or objects as their index while properties and functions do take them as their possible arguments.
I can declare the type of a class by declaring:
type
TMyObject = class(TSomething);
TMyObjectClass = class of TMyObject;
I'm trying to do something like this:
IData<TIn,TOut> = interface;
IData = interface
function GetGenericData<Tin,TOut>: IData<TInput,TOut>;
function GetInType: TRttiType;
function GetOutType: TRttiType;
end;
Declare a base type that can give access to the generic type and give me info on what the generic Input and Output types are.
IData<TIn,TOut> = interface(IData)
['{5B402458-22EC-4A8B-83F3-C11AC575B79E}']
function GetInput(Index: Integer): TIn;
function GetInputCount: Integer;
function GetOutput(Index: Integer): TOut;
function GetOutputCount: Integer;
property Input[index: integer]: TIn read GetInput;
property Output[index: integer]: TOut read GetOutput;
property InputCount: integer read GetInputCount;
property OutputCount: integer read GetOutputCount;
end;
Here is the actual generic type that holds an 2 arrays of data. Note that the input and output does not need to be the same type.
I then have a class that contains one or more different types of IData.
TStage = class(TPipelineStage, IData);
TStage<TIn, TOut> = class(TStage, IData<TIn, TOut>);
TMyPipeline = class
fStages = TArray<TStage>; <<-- this is really a list of TStage<?,?>
I want to have a list of different TStages in my class, but obviously I cannot code that.
How do I access the TStage<IInterfaceA, InterfaceB> and TStage<InterfaceB, InterfaceB> from fStages?
Can I use class of .... in this context and instantiate an object from there?
The reason I'm using this approach is that I'm using a delegate in the Pipeline stage that is declared thus:
TDelegate<TIn, TOut> = reference to procedure(const Data: IData<TIn, TOut>);
There are a limitation in Delphi language that will prevent you to do things exactly the way you are trying. Take the code:
IData<TIn,TOut> = interface;
IData = interface
function GetGenericData<Tin,TOut>: IData<TInput,TOut>;
function GetInType: TRttiType;
function GetOutType: TRttiType;
end;
Here you have a generic method in a interface. Delphi (at least until XE3) does not support generic methods in interfaces.
In other snipet you have:
TStage = class(TPipelineStage, IData);
TStage<TIn, TOut> = class(TStage, IData<TIn, TOut>);
TMyPipeline = class
fStages = TArray<TStage>; <<-- this is really a list of TStage<?,?>
The answer for the question in code is No. That´s an array, not a list. However, since your array is holding instances of TStage, it will also hold instances of TStage<TIn, TOut> with no problem, no matter what types are TIn and TOut.
You have this question:
I want to have a list of different TStages in my class, but obviously I cannot code that.
How do I access the TStage and TStage from fStages?
Actually, you can! It´s possible to declare a list of a certain type (TStage in your case) and hold actual instances of descending classes, even a generic subclass.
It seems to me that you want a generic method to return the TStage instance already typed to a descending type, in order to avoid a type cast and some type tests, eventually returning nil if the stage is an instance of another class, right?
In this case, a generic method can be helpful, but only in classes, not in interfaces. I would do something like this (I didn´t have Delphi at hand to test the code, but the idea seems to fit your needs):
interface
type
TMyPipeline = class
private
FStages: TObjectList<TStage>;
public
// Constructors, destructor and other methods...
function StageAs<TIn, TOut>(aIndex: Integer): TStage<TIn, TOut>;
end;
implementation
function TMyPipeline.StageAs<TIn, TOut>(aIndex: Integer): TStage<TIn, TOut>;
var
stage: TStage;
begin
stage := FStages[aIndex];
if stage.InheritsFrom(TStage<TIn, TOut>) then
Result := TStage<TIn, TOut>(stage)
else
Result := nil;
end;
I have a generic List-like class tMyList<B> with a method Each() which iterated over each element and calls anonymous procedure tMyList<A>.enumProc with paramenter - the current item of type <B>.
I want to implement the class as an Interface for easier lifetime management.
The problem is I cannot declare the Each method in the iMyList<A> interface, because tMyList<A>.enumProc type is unknown. As far as I know Interfaces does not support nested types?
Here is the code:
tMyList<B> = class;
iMyList<A> = interface
procedure each(enumProcedure: iMyList<A>.enumProc); // ERROR - Undeclared identifier: 'enumProc'
end;
tMyList<B> = class(tInterfacedObject, iMyList<B>)
type
enumProc = reference to procedure(item: iMyList<B>);
public
procedure each(enumProcedure: enumProc);
end;
* Implementing Enumerator is not an option in this particular case
The only way that you can make this work is to define the procedural type outside of the implementing class. Like this:
type
IMyIntf<A> = interface;
TMyProc<A> = reference to procedure(Intf: IMyIntf<A>);
IMyIntf<A> = interface
procedure Foo(Proc: TMyProc<A>);
end;
TMyClass<A> = class(TInterfacedObject, IMyIntf<A>)
procedure Foo(Proc: TMyProc<A>);
end;
Consider the following types
type
TRecs = array[0..100000] of TRec;
PRecs = ^TRecs;
TRecObject = class
private
fRecs: PRecs;
public
constructor Create;
property Recs: PRecs read fRecs;
end;
I would like to make TRec a generic parameter. The problem is that I need to place outside of the class scope. Because something like
T<MyType>Object = class
private
fRecs: ^array[0..100000] of MyType;
public
property Recs: ^array[0..100000] of MyType read fRecs
end
is not possible.
Making PRecs a parameter also is not an option because there is TRec-related code in my actual object.
Is there a solution in modern Object Pascal? And if not, just curious is there any other generic-enabled language that can solve something like this?
I'm not entirely sure I understand your question, but I think you are looking for something like this:
type
TMyObject<T> = class
public
type
PArr = ^TArr;
TArr = array[0..100000] of T;
private
fRecs: PArr;
public
property Recs: PArr read fRecs
end;
That said, I can't see the point of that class. You could just use TList<T> from Generics.Collections.
And if your need an array, then you can use a dynamic array: TArray<T> or array of T, as you prefer.
You got your generic syntax a bit muddled up. Try this:
TRecArray<T> = array[0..100000] of T;
TGenericRecObject<T> = class
private
FRecs: TRecArray<T>;
public
property Recs: TRecArray<T> read FRecs;
end;