How do I declare a variable of a generic type without knowing the type arguments? - delphi

How do I define a generic TList type so that I can declare a variable of that type and then assign any specialization of TList<> to it?
I want to declare this variable:
var
MyList:THowToDeclareThisListType<T>;
And then instantiate it like this:
MyList:=THowToDeclareThisListType<integer>.Create;
or
MyList:=THowToDeclareThisListType<double>.Create;
etc. I must be missing something pretty obvious here. I don't want classes, just a simple type definition.

You are trying to declare a variable like this:
var
List: TList<?>;
such that List can be assigned objects of type TList<Integer> or TList<Double> or TList<string>.
That is not possible. When you define a variable using a generic type, the type must be fully instantiated.
The only way that you can have a variable that holds any object of type TList<T> is if the variable is declared to have a common base class to TList<T>. And the common base class cannot be a non-instantiated generic. For TList<T> the only possible common base class is TObject.
So you could write
var
List: TObject;
and then assign any of your objects to List. But I'm not sure that would be terribly useful!

Related

How to define a thread local variable of a generic type in Delphi

I would like to define a thread local variable of the following generic type:
type
TSession<T: TEntity> = class(TInterfacedObject, ISession<T>);
I tried to define the variable with the threadvar keyword but I am having problems because of the generic parameter:
threadvar
mySession: ISession<T>; // not working
What is the recommended way for defining a thread local variable of a generic type in Delphi?
You cannot declare a variable of an open generic type outside of a generic type (or method), and that has nothing to do with being a threadvar.
Either put the threadvar inside a generic type (of course it has to be a class threadvar) that knows what type of T for your ISession<T> you are using or use a non generic base type from which ISession<T> inherits.
Also you have to know that you may create a memory leak here because threadvars are not implicitly finalized (see here) - you have to take care of that.

Type inheritance

In a class unit I have the type
type
TFolderType = (
dirRoot,
dirDatabase,
dirDocs,
dirConfig,
dirBackup,
dirDown,
dirUp,
dirScripts,
dirLicense,
dirImages,
dirMail,
dirProjects,
dirInput,
dirOutput
);
Now I would like to inherit this class from another class and add some extra elements
Is that in any way possible or can I do this in another way
I have thought of creating a class with all the elements as properties but I am not sure if that is the way to go
Like David says, it is not a class.
As an alternative, you can declare your bigger enumeration like:
type
TThingType = (dirThingA, dirRoot, dirDataBase, ..., dirOutput, dirThingY, dirThingZ);
And then declare your TFolderType as:
type
TFolderType = dirRoot..dirOutput;
Some concerns:
A folder 'needs' to be of type thing
The prefix dir 'needs' to be meaningful for both thing and folder
Current code that assumes enumeration index of the TFolderType elements needs to be rewritten, or add all 'new' elements in the back.
That is not class, rather it is an enumerated type. You cannot use inheritance with enumerated types. You will need to create a new enumerated type. Or perhaps solve the problem using something other than an enumerated type.

What does the keyword `constructor` mean in the class title?

If I have a class declaration like this one:
MyCollection<T: TBaseCopyable, constructor> = class
What does the keyword constructor do?
Doesn't every class have a constructor already, what is it up doing there?
It is a generic constraint.
Constraints can be associated with a type parameter of a generic. Constraints declare items that must be supported by any particular type passed to that parameter in a construction of the generic type.
This particular constraint is the constructor constraint:
A type parameter may be constrained by zero or one instance of the reserved word "constructor". This means that the actual argument type must be a class that defines a default constructor (a public parameterless constructor), so that methods within the generic type may construct instances of the argument type using the argument type's default constructor, without knowing anything about the argument type itself (no minimum base type requirements).
In a constraint declaration, you can mix "constructor" in any order with interface or class type constraints.
In my opinion it's a largely useless feature. Every time I've written a generic container class that wishes to instantiate members, I've found that I needed to be able to pass parameters to the constructor. I have absolutely no idea why the feature exists in this crippled form.
There is a well-known technique that allows generic containers to instantiate members, discussed here: Generics constructor with parameter constraint?

Store Generic Array in Class using Delphi XE

Using the structure below, how can I define my TAnimalCollection class in order to store my collection? Calling either SelectAll or SelectTop10 will update the SelectedRecords.
Removing the private field allows the code to compile, but there is no mechanism to then store the returned result set.
TDog = class
private
FBreed: string;
public
property Breed: string read FBreed write FBreed;
end;
TCat = class
private
IsWild: string;
public
property IsWild: string read FIsWild write FIsWild;
end;
TMyArray<T> = array of T;
TAnimalCollection = class
private
SelectedRecords: TMyArray<T>; // Generates: Undeclared Identifier: 'T'
public
function SelectAll<T>: TMyArray<T>;
function SelectTop10<T>: TMyArray<T>;
// Other Methods
end;
First, you don't need TMyArray; the built-in TArray type does the same thing.
The compiler is correct, though. In your field declaration, there's no such thing as T. The generic argument needs to be introduced on the left of a declaration before it can be used on the right. If Delphi supported generic fields, the declaration would look like this:
SelectedRecords<T>: TArray<T>;
But it doesn't, and you wouldn't want it to in this case anyway. You apparently want to store two completely unrelated classes together in the same array simultaneously. An array is always of a single type. The only single type that unifies TDog and TCat is TObject, so your array needs to be of that type:
SelectedRecords: TArray<TObject>;
// or, more conventionally,
SelectedRecords: array of TObject;
You're welcome to declare a "generic array," but only as a field of a generic class or a variable of a generic method. If you could declare a standalone generic array, try to think of when the actual type of the array elements would be determined. If not at the point you declare the array, then when? With classes and methods, you specify the type argument(s) when you declare a variable of the class, instantiate the class, or call the method. Those are uses that are separate from their declarations, and each use is distinct. When you declare a variable, you must use it the same way you declared it — a variable's type cannot change without recompiling the program.

Interfaces and properties

Is it possible to declare a property in an interface without declaring the get- and set-methods for it? Something like:
IValue = interface
property value: double;
end;
I want to state that the implementor should have a property called value, returning a double, but I really don't care if it returns a private field or the result from a function.
If it is possible, is it possible to declare it read/write or read-only?
No. Interfaces are implemented as function tables (basically a simple virtual method table) and the compiler needs to know there's a function to map the property onto. You can declare a property on an interface, but it has to have functions as getter/setter values, not fields. You can make it read-only or write-only, though.
When working with properties in an interface, think of the property as a shortcut to the reader/writer. Only one is required to satisfy the shortcut...otherwise it doesn't point to anything.

Resources