Jump to content

Recommended Posts

can you suggest me a good tutorial about Delphi generics?

especially, when and where they are useful? in which purposes?

performance wyse are they trustable?

Share this post


Link to post

 

As a reaction to one of his answers during Q&A I wrote a blog post.

Having said that and personally loving generics for various use cases (as shown in the blog post) there are also things that are solved sub optimal - which I also wrote about.

Also if you have used generics in C# then you will likely miss co- and contravariance - oh, look, I also wrote about that.

If you are going really fancy with generics and code that uses RTTI you have to be aware about some percularities - guess what: wrote about it.

 

Now because in generics you basically have the lowest common denominator and we are lacking quite some ways to specify some traits of the supported types via constraints there are several things that you cannot do or have to fall back to indirections: most common example is using comparer interfaces for generic sorting algorithm or hashtables. That is mostly where a naively implemented generic algorithm might be slower than some handcrafted code for the specific type unless you heavily optimize for various cases (as I have done in Spring).

Edited by Stefan Glienke
  • Like 6

Share this post


Link to post
14 hours ago, RDP1974 said:

when and where they are useful? in which purposes?

It's mostly about containers.

You can have TList containing any type without ugly casting to/from Pointer.

 

Edited by Fr0sT.Brutal

Share this post


Link to post
4 hours ago, Fr0sT.Brutal said:

It's mostly about containers.

Apart from the myriad of other applications that aren't about containers

  • Like 3

Share this post


Link to post
54 minutes ago, David Heffernan said:

Apart from the myriad of other applications that aren't about containers

Name at least 10 of that myriad?

I personally meet them in:

- containers

- my syntax-sugaring enum/set wrapper

- Virtualtreeview's GetNodeData - might be considered container stuff as well

 

I also saw template-alike application (TProc2 = procedure <T1,T2>) but it's hardly a key feature IMHO

Share this post


Link to post

I use generics a lot in non container/collection scenarios - for example Delphi Mocks fluent api uses the generic type to allow a type safe definition of the mock. Without generics we would be using strings - which is not typesafe and would not survive refactoring.

 

Another example -  I have lexer/parser library (used in FinalBuilder) 

//NOTE : T MUST be an Enumerated Type (need better constraints!)
  TTokenRec<T> = record
  private
  .....
  end;
 
 ILexer<T> = interface
    function Next       : TTokenRec<T>;
 ...
  
 TBaseLexer<T> = class(TInterfacedObject,ILexer<T>)
 
 //concrete usages
 TDSLLexer = class(TBaseLexer<TDSLTokenKind>,IDSLLexer)
 TVariableSenseLexer = class(TBaseLexer<TTokenKind>)
 
 //parsers built on top of the lexers
  IParser<TAstNodeType,TParseErrorType> = interface
 TBaseParser<TTokenType,TAstNodeType,TParseErrorType> = class(TInterfacedObject,IParser<TAstNodeType,TParseErrorType>)

 TDSLParser = class(TBaseParser<TDSLTokenKind,TDSLASTNodeType,TDSLParserErrorType>)
 TVariableSenseParser = class (TBaseParser<TTokenKind, TVariableSenseASTNodeType, TVariableSenseParserErrorType>)  

Generics allows you to avoid copying and pasting tons of boilerplate code, changing types etc, or doing having to do tons of nasty type casting.  

 

If Delphi's generics were better there would be many more uses for them, but when you attempt anything complex you run into limitations.  If you really want to know what else can be done with generics, you would have to look at other languages that have better generics implementations (like c#). 

 

  • Like 4

Share this post


Link to post

Think of collections as "algorithms and datatypes for any type" - then you know the use case of generics. For any algorithm and/or datatype that is not just specific for one exact type.

Share this post


Link to post
21 hours ago, Fr0sT.Brutal said:

Name at least 10 of that myriad?

I personally meet them in:

- containers

- my syntax-sugaring enum/set wrapper

- Virtualtreeview's GetNodeData - might be considered container stuff as well

 

I also saw template-alike application (TProc2 = procedure <T1,T2>) but it's hardly a key feature IMHO

 

From my code base I find this:

  TThreadsafe<T> = class
  private
    FLock: TCriticalSection;
    FValue: T;
    function GetValue: T;
    procedure SetValue(const NewValue: T);
  public
    constructor Create;
    destructor Destroy; override;
    property Value: T read GetValue write SetValue;
  end;

And this:

  Enum<T: record> = class
  strict private
    class function TypeInfo: PTypeInfo; static;
    class function TypeData: PTypeData; static;
  public
    class function IsEnum: Boolean; static;
    class function Count: Integer; static;
    class function ToOrdinal(Value: T): Integer; static;
    class function FromOrdinal(Value: Integer): T; static;
    class function TryFromOrdinal(Value: Integer; out Enum: T): Boolean; static;
    class function ToString(Value: T): string; static;
    class function FromString(const Value: string): T; static;
    class function MinValue: Integer; static;
    class function MaxValue: Integer; static;
    class function InRange(Value: Integer): Boolean; static;
    class function EnsureRange(Value: Integer): Integer; static;
    class function FromName(const Name: string): T; static;
    class function TryFromName(const Name: string; out Enum: T): Boolean; static;
    class function ToName(Item: T): string; static;
    class function ToNewSentenceName(Item: T): string; static;
    class function ToMidSentenceName(Item: T): string; static;
    class function ToUpperCaseName(Item: T): string; static;
    class function ToPascalCaseName(Item: T): string; static;
  end;

And this:

  TArray = class
  public
    type
      TWriteItem<T> = reference to procedure(const TaggedFile: ITaggedFile; const Item: T);
      TReadItem<T> = reference to procedure(const TaggedFile: ITaggedFile; out Item: T);
  strict private
    const
      SortOrderFactor: array [TSortOrder] of Integer = (1, -1);
  public
    class procedure Swap<T>(var Left, Right: T); static;
    class procedure Reverse<T>(var Values: array of T; Index, Count: Integer); overload; static;
    class procedure Reverse<T>(var Values: array of T); overload; static;
    class function Reversed<T>(const Values: array of T): TArray<T>; static;
    class procedure Shuffle<T>(var Values: array of T; const Random: TFunc<Integer, Integer>; Index, Count: Integer); overload; static;
    class procedure Shuffle<T>(var Values: array of T; const Random: TFunc<Integer, Integer>); overload; static;
    class function Contains<T>(const Values: array of T; const Item: T; const Comparer: IEqualityComparer<T>; Index, Count: Integer; out ItemIndex: Integer): Boolean; overload; static;
    class function Contains<T>(const Values: array of T; const Item: T; const Comparer: IEqualityComparer<T>; out ItemIndex: Integer): Boolean; overload; static;
    class function Contains<T>(const Values: array of T; const Item: T; const Comparer: IEqualityComparer<T>; Index, Count: Integer): Boolean; overload; static;
    class function Contains<T>(const Values: array of T; const Item: T; const Comparer: IEqualityComparer<T>): Boolean; overload; static;
    class function Contains<T>(const Values: array of T; const Item: T; EqualOp: TEqualOp<T>; Index, Count: Integer; out ItemIndex: Integer): Boolean; overload; static;
    class function Contains<T>(const Values: array of T; const Item: T; EqualOp: TEqualOp<T>; out ItemIndex: Integer): Boolean; overload; static;
    class function Contains<T>(const Values: array of T; const Item: T; EqualOp: TEqualOp<T>; Index, Count: Integer): Boolean; overload; static;
    class function Contains<T>(const Values: array of T; const Item: T; EqualOp: TEqualOp<T>): Boolean; overload; static;
    class function Contains<T>(const Values: array of T; const Item: T; Index, Count: Integer; out ItemIndex: Integer): Boolean; overload; static;
    class function Contains<T>(const Values: array of T; const Item: T; out ItemIndex: Integer): Boolean; overload; static;
    class function Contains<T>(const Values: array of T; const Item: T; Index, Count: Integer): Boolean; overload; static;
    class function Contains<T>(const Values: array of T; const Item: T): Boolean; overload; static;
    class function Matches<T>(const Values: array of T; const Predicate: TPredicate<T>; out ItemIndex: Integer): Boolean; overload; static;
    class function Matches<T>(const Values: array of T; const Predicate: TPredicate<T>): Boolean; overload; static;
    class function Matches<T>(const Values: array of T; const Predicate: TPredicateOfObj<T>; out ItemIndex: Integer): Boolean; overload; static;
    class function Matches<T>(const Values: array of T; const Predicate: TPredicateOfObj<T>): Boolean; overload; static;
    class function IndexOf<T>(const Values: array of T; const Item: T; const Comparer: IEqualityComparer<T>; Index, Count: Integer): Integer; overload; static;
    class function IndexOf<T>(const Values: array of T; const Item: T; const Comparer: IEqualityComparer<T>): Integer; overload; static;
    class function IndexOf<T>(const Values: array of T; const Item: T; EqualOp: TEqualOp<T>; Index, Count: Integer): Integer; overload; static;
    class function IndexOf<T>(const Values: array of T; const Item: T; EqualOp: TEqualOp<T>): Integer; overload; static;
    class function IndexOf<T>(const Values: array of T; const Item: T; Index, Count: Integer): Integer; overload; static;
    class function IndexOf<T>(const Values: array of T; const Item: T): Integer; overload; static;
    class function Equal<T>(const lhs, rhs: array of T; const Comparer: IEqualityComparer<T>): Boolean; overload; static;
    class function Equal<T>(const lhs, rhs: array of T; EqualOp: TEqualOp<T>): Boolean; overload; static;
    class function Equal<T>(const lhs, rhs: array of T): Boolean; overload; static;
    class function Ordered<T>(const Values: array of T; const Comparer: IComparer<T>; Index, Count: Integer): Boolean; overload; static;
    class function Ordered<T>(const Values: array of T; const Comparer: IComparer<T>): Boolean; overload; static;
    class function Ordered<T>(const Values: array of T; const Comparison: TComparison<T>; Index, Count: Integer): Boolean; overload; static;
    class function Ordered<T>(const Values: array of T; const Comparison: TComparison<T>): Boolean; overload; static;
    class function Ordered<T>(const Values: array of T; Index, Count: Integer): Boolean; overload; static;
    class function Ordered<T>(const Values: array of T): Boolean; overload; static;
    class function HasDuplicates<T>(const Values: array of T; const Comparer: IEqualityComparer<T>; out Value: T; Index, Count: Integer): Boolean; overload; static;
    class function HasDuplicates<T>(const Values: array of T; const Comparer: IEqualityComparer<T>; out Value: T): Boolean; overload; static;
    class function HasDuplicates<T>(const Values: array of T; EqualOp: TEqualOp<T>; out Value: T; Index, Count: Integer): Boolean; overload; static;
    class function HasDuplicates<T>(const Values: array of T; EqualOp: TEqualOp<T>; out Value: T): Boolean; overload; static;
    class function HasDuplicates<T>(const Values: array of T; out Value: T; Index, Count: Integer): Boolean; overload; static;
    class function HasDuplicates<T>(const Values: array of T; out Value: T): Boolean; overload; static;
    class function HasDuplicates<T>(const Values: array of T): Boolean; overload; static;
    class function HasDuplicates<T>(const Values: array of T; const Comparer: IComparer<T>; out Value: T; Index, Count: Integer): Boolean; overload; static;
    class function HasDuplicates<T>(const Values: array of T; const Comparer: IComparer<T>; out Value: T): Boolean; overload; static;
    class function HasDuplicates<T>(const Values: array of T; const Comparison: TComparison<T>; out Value: T; Index, Count: Integer): Boolean; overload; static;
    class function HasDuplicates<T>(const Values: array of T; const Comparison: TComparison<T>; out Value: T): Boolean; overload; static;
    class function HasDuplicates<T>(const Values: array of T; const Comparison: TComparison<T>): Boolean; overload; static;
    class function RemoveDuplicates<T>(var Values: array of T; const Comparer: IEqualityComparer<T>; Index, Count: Integer; const Dispose: TProcOfObj<T>): Integer; overload; static;
    class function RemoveDuplicates<T>(var Values: array of T; const Comparer: IEqualityComparer<T>; Index, Count: Integer): Integer; overload; static;
    class function RemoveDuplicates<T>(var Values: array of T; const Comparer: IEqualityComparer<T>): Integer; overload; static;
    class function RemoveDuplicates<T>(var Values: array of T; EqualOp: TEqualOp<T>; Index, Count: Integer; const Dispose: TProcOfObj<T>): Integer; overload; static;
    class function RemoveDuplicates<T>(var Values: array of T; EqualOp: TEqualOp<T>; Index, Count: Integer): Integer; overload; static;
    class function RemoveDuplicates<T>(var Values: array of T; EqualOp: TEqualOp<T>): Integer; overload; static;
    class function RemoveDuplicates<T>(var Values: array of T; const Comparer: IComparer<T>; Index, Count: Integer; const Dispose: TProcOfObj<T>): Integer; overload; static;
    class function RemoveDuplicates<T>(var Values: array of T; const Comparer: IComparer<T>; Index, Count: Integer): Integer; overload; static;
    class function RemoveDuplicates<T>(var Values: array of T; const Comparer: IComparer<T>): Integer; overload; static;
    class function RemoveDuplicates<T>(var Values: array of T; const Comparison: TComparison<T>; Index, Count: Integer): Integer; overload; static;
    class function RemoveDuplicates<T>(var Values: array of T; const Comparison: TComparison<T>): Integer; overload; static;
    class function RemoveDuplicates<T>(var Values: array of T; Index, Count: Integer): Integer; overload; static;
    class function RemoveDuplicates<T>(var Values: array of T): Integer; overload; static;
    class function Sorted<T>(const Values: array of T; const Comparer: IComparer<T>; Order: TSortOrder; Index, Count: Integer): Boolean; overload; static;
    class function Sorted<T>(const Values: array of T; const Comparer: IComparer<T>; Index, Count: Integer): Boolean; overload; static;
    class function Sorted<T>(const Values: array of T; const Comparer: IComparer<T>; Order: TSortOrder): Boolean; overload; static;
    class function Sorted<T>(const Values: array of T; const Comparer: IComparer<T>): Boolean; overload; static;
    class function Sorted<T>(const Values: array of T; const Comparison: TComparison<T>; Order: TSortOrder; Index, Count: Integer): Boolean; overload; static;
    class function Sorted<T>(const Values: array of T; const Comparison: TComparison<T>; Index, Count: Integer): Boolean; overload; static;
    class function Sorted<T>(const Values: array of T; const Comparison: TComparison<T>; Order: TSortOrder): Boolean; overload; static;
    class function Sorted<T>(const Values: array of T; const Comparison: TComparison<T>): Boolean; overload; static;
    class function Sorted<T>(const Values: array of T; Order: TSortOrder; Index, Count: Integer): Boolean; overload; static;
    class function Sorted<T>(const Values: array of T; Index, Count: Integer): Boolean; overload; static;
    class function Sorted<T>(const Values: array of T; Order: TSortOrder): Boolean; overload; static;
    class function Sorted<T>(const Values: array of T): Boolean; overload; static;
    class procedure Sort<T>(var Values: array of T; const Comparer: IComparer<T>; Order: TSortOrder; Index, Count: Integer); overload; static;
    class procedure Sort<T>(var Values: array of T; const Comparer: IComparer<T>; Index, Count: Integer); overload; static;
    class procedure Sort<T>(var Values: array of T; const Comparer: IComparer<T>; Order: TSortOrder); overload; static;
    class procedure Sort<T>(var Values: array of T; const Comparer: IComparer<T>); overload; static;
    class procedure Sort<T>(var Values: array of T; const Comparison: TComparison<T>; Order: TSortOrder; Index, Count: Integer); overload; static;
    class procedure Sort<T>(var Values: array of T; const Comparison: TComparison<T>; Index, Count: Integer); overload; static;
    class procedure Sort<T>(var Values: array of T; const Comparison: TComparison<T>; Order: TSortOrder); overload; static;
    class procedure Sort<T>(var Values: array of T; const Comparison: TComparison<T>); overload; static;
    class procedure Sort<T>(var Values: array of T; Order: TSortOrder; Index, Count: Integer); overload; static;
    class procedure Sort<T>(var Values: array of T; Index, Count: Integer); overload; static;
    class procedure Sort<T>(var Values: array of T; Order: TSortOrder); overload; static;
    class procedure Sort<T>(var Values: array of T); overload; static;
    class function Copy<T>(const Source: array of T; Index, Count: Integer): TArray<T>; overload; static;
    class function Copy<T>(const Source: array of T): TArray<T>; overload; static;
    class procedure Move<T>(const Source: array of T; var Dest: array of T; Index, Count: Integer); overload; static;
    class procedure Move<T>(const Source: array of T; var Dest: array of T); overload; static;
    class function Concatenated<T>(const Source1, Source2: array of T): TArray<T>; overload; static;
    class function Concatenated<T>(const Source: array of TArray<T>): TArray<T>; overload; static;
    class procedure Initialise<T>(var Values: array of T; const Value: T); static;
    class function New<T>(Count: Integer; const Value: T): TArray<T>; static;
    class function Zero<T>(Count: Integer): TArray<T>; static;
    class procedure Zeroise<T>(var Values: array of T); static;
    class procedure Free<T: class>(const Values: array of T); static;
    class procedure FreeAndNil<T: class>(var Values: array of T); static;
    class function GetHashCode<T>(const Values: array of T; const Comparer: IEqualityComparer<T>): Integer; overload; static;
    class function GetHashCode<T>(const Values: array of T): Integer; overload; static;
    class function GetHashCode<T>(Values: Pointer; Count: Integer; const Comparer: IEqualityComparer<T>): Integer; overload; static;
    class function GetHashCode<T>(Values: Pointer; Count: Integer): Integer; overload; static;
    class procedure Write<T>(const TaggedFile: ITaggedFile; const WriteItem: TWriteItem<T>; const Values: TArray<T>); overload; static;
    class procedure Write<T>(const TaggedFile: ITaggedFile; const Values: TArray<T>); overload; static;
    class procedure Read<T>(const TaggedFile: ITaggedFile; const ReadItem: TReadItem<T>; out Values: TArray<T>); overload; static;
    class procedure Read<T>(const TaggedFile: ITaggedFile; out Values: TArray<T>); overload; static;
    class procedure Skip(const TaggedFile: ITaggedFile); static;
  end;

And this:

  NDArray<T> = record
  public
    type
    {$POINTERMATH ON}
      P = ^T;
    {$POINTERMATH OFF}
  private
    type
      TEnumerator = record
      private
        FOwner: ^NDArray<T>;
        FCurrentIndices: TArray<Integer>;
        function GetCurrent: T;
      public
        class function New(const Owner: NDArray<T>): TEnumerator; static;
        property Current: T read GetCurrent;
        function MoveNext: Boolean;
      end;
  private
    FBase: P;
    FValues: TArray<T>;
    FRank: Integer;
    FShape: TArray<Integer>;
    FStride: TArray<NativeInt>;
    function LinearIndex(const Indices: array of Integer): NativeInt;
    function GetCount: NativeInt;
    function GetItem(const Indices: array of Integer): T;
    procedure SetItem(const Indices: array of Integer; const Value: T);
    function GetSlice(const Indices: array of Integer): NDArray<T>;
    procedure SetSlice(const Indices: array of Integer; const Value: NDArray<T>);
    function GetIsEmpty: Boolean;
    function GetHasZeroDimension: Boolean;
  public
    class function New(const Shape: array of Integer): NDArray<T>; overload; static;
    class function New(const Shape: array of Integer; const Values: TArray<T>): NDArray<T>; overload; static;
    class function New(const Shape: array of Integer; const Value: T): NDArray<T>; overload; static;
    class function Zero(const Shape: array of Integer): NDArray<T>; static;
    class function Diagonal(const Values: array of T): NDArray<T>; overload; static;
    class function Diagonal(Size: Integer; const Value: T): NDArray<T>; overload; static;
    class function Empty: NDArray<T>; static;
    class operator Explicit(const arr: TArray<T>): NDArray<T>;
    property IsEmpty: Boolean read GetIsEmpty;
    property HasZeroDimension: Boolean read GetHasZeroDimension;
    property Rank: Integer read FRank;
    property Shape: TArray<Integer> read FShape;
    property Stride: TArray<NativeInt> read FStride;
    property Count: NativeInt read GetCount;
    property DataPtr: P read FBase;
    property Items[const Indices: array of Integer]: T read GetItem write SetItem; default;
    function ItemPtr(const Indices: array of Integer): P;
    property Slice[const Indices: array of Integer]: NDArray<T> read GetSlice write SetSlice;
    procedure CopyTo(Dest: P; Count: NativeInt);
    function Clone: NDArray<T>;
    function ToFlattenedArray: TArray<T>;
    class procedure Write(const TaggedFile: ITaggedFile; const WriteItem: TArray.TWriteItem<T>; const Value: NDArray<T>); overload; static;
    class procedure Write(const TaggedFile: ITaggedFile; const Value: NDArray<T>); overload; static;
    class procedure Read(const TaggedFile: ITaggedFile; const ReadItem: TArray.TReadItem<T>; out Value: NDArray<T>); overload; static;
    class procedure Read(const TaggedFile: ITaggedFile; out Value: NDArray<T>); overload; static;
  public
    function GetEnumerator: TEnumerator;
  end;

And this:

  TIterativeSolver<T> = class
  public
    type
      P = ^T;
  protected
    class procedure AGSIterate(A, b, x, work: P; N: Integer; Storage: TMatrixStorage); static;
    class procedure AGSCalcResidual(A, b, x, r: P; N: Integer; Storage: TMatrixStorage); static;
    class function AGSIsZero(b: P; N: Integer): Boolean; static;
    class function AGSSqrMag(x: P; N: Integer): Double; static;
    class function AGSAccel(r, x: P; work: Pointer; iter, N: Integer): Boolean; static;
  public
    class function SolveAGS(const A: NDArray<T>; var b: NDArray<T>; maxiter: Integer; tol: Double; out iter: Integer): Boolean; static;
  end;

And this:

type
  TLUSolver<T> = class
  public
    type
      P = ^T;

      TWorkspace = record
      public
        ipiv: TArray<Integer>;
      public
        procedure Update(N: Integer);
      end;
  protected //protected to avoid spurious compiler warning
    class procedure DecomposeDense(A: P; ipiv: PInteger; N: Integer); overload; static;
    class procedure SubstituteDense(A: P; ipiv: PInteger; N: Integer; b: P; Storage: TMatrixStorage); static;
    class procedure DecomposeBanded(A: P; ipiv: PInteger; N, Bandwidth, ldab: Integer); overload; static;
    class procedure SubstituteBanded(A: P; ipiv: PInteger; N, Bandwidth, ldab: Integer; b: P; Storage: TMatrixStorage); static;
    class procedure DecomposeDense(A: P; N: Integer; var Workspace: TWorkspace); overload; static;
    class procedure DecomposeBanded(A: P; N, Bandwidth, ldab: Integer; var Workspace: TWorkspace); overload; static;
  public
    class procedure Decompose(var A: NDArray<T>; var Workspace: TWorkspace); static;
    class procedure Substitute(var A, b: NDArray<T>; const Workspace: TWorkspace); static;
    class procedure Solve(var A, b: NDArray<T>); static;
  end;

And this:

          TData<T> = record
            x: T;
            xPrime: TArray<T>;
            xPrimePrime: TArray<TArray<T>>;
            xPrimePrimePrime: TArray<TArray<TArray<T>>>;
          end;

And this:

  TTableItem<T: TModelObject> = record
  public
    ModelObject: T;
    ObjectIndex: Integer;
    ItemIndex: Integer;
  public
    class function New(ModelObject: T; ObjectIndex, ItemIndex: Integer): TTableItem<T>; static;
    class function DisplayName(ModelObject: TModelObject; const ItemName: string; ItemIndex: Integer): string; overload; static;
    function DisplayName(const ItemName: string): string; overload;
    procedure RedirectDataAccess(var Handler: TDataObject; var Index: Integer);
  end;

 

I could go on, but it's pretty boring.  And these are just some examples from one particular code base.  Other code bases will have different use cases.

 

As Stefan said, generics are used for generic programming.

Quote

Generic programming is a style of computer programming in which algorithms are written in terms of types to-be-specified-later that are then instantiated when needed for specific types provided as parameters. This approach, pioneered by the ML programming language in 1973,[1][2] permits writing common functions or types that differ only in the set of types on which they operate when used, thus reducing duplication. Such software entities are known as generics in Ada, C#, Delphi, Eiffel, F#, Java, Nim, Python, Go, Rust, Swift, TypeScript and Visual Basic .NET. They are known as parametric polymorphism in ML, Scala, Julia, and Haskell (the Haskell community also uses the term "generic" for a related but somewhat different concept); templates in C++ and D; and parameterized types in the influential 1994 book Design Patterns.[3]

 

 

So yeah, a myriad.

Edited by David Heffernan
  • Like 1

Share this post


Link to post
32 minutes ago, David Heffernan said:

From my code base I find this:

Well, 3 samples from these are containers and 1 is enum wrapper 😛

But OK, I got your point. Just haven't used generics massively myself

Share this post


Link to post

Delphi language is evolved a lot in the last years

should be very useful a blog where to show the new language capabilities

 

btw. example

public

type

TWriteItem<T> = reference to procedure(const TaggedFile: ITaggedFile; const Item: T);

 

a type inside a class?

what is a reference to procedure?

2 hours ago, Stefan Glienke said:

Think of collections as "algorithms and datatypes for any type" - then you know the use case of generics. For any algorithm and/or datatype that is not just specific for one exact type.

great, under the hood the enumeration how it is engineered? hash table? binary-search-tree? so the compiler will produce "bloat" code for every generic class if I see, else how to solve the fact that the type it is not defined before???

Share this post


Link to post
58 minutes ago, Fr0sT.Brutal said:

3 samples from these are containers

I don't really see anything that is what I would describe as a container / collection.

Share this post


Link to post
21 minutes ago, RDP1974 said:

a type inside a class?

Yes, nested types. Really just a type declared in the lexical scope of the containing type.

 

22 minutes ago, RDP1974 said:

what is a reference to procedure?

Delphi syntax for anonymous methods.

Share this post


Link to post
3 hours ago, David Heffernan said:

I don't really see anything that is what I would describe as a container / collection.

Isn't array a container?

Share this post


Link to post
4 minutes ago, Fr0sT.Brutal said:

Isn't array a container?

An array is a container, but that TArray isn't an array, it's a class containing a lot of static methods.

Share this post


Link to post

Hi, I like to use it in this way.: (here you will find example files)

 

I think the best book for generics.: Pawel Glowacki (RIP) - Expert Delphi

How to separate units, back and front end, types etc..

 

Edited by skyzoframe[hun]

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×