[fpc-devel] Generics Basics

Marc Weustink marc at dommelstein.net
Wed Nov 9 00:11:55 CET 2005


L505 wrote:
>>The Very Big Advantage (Tm), is that you get syntax checking, while still
>>using a type diversely. That's impossible to do (at compile-time) without
>>generics.
>>
>>Probably the best example of this is something like TList:
>>
>>Without generics:
>>
>>TOrange = class ... end;
>>TApple  = class ... end;
>>
>>var
>>  T: TList;
>>begin
>>  T := TList.Create();
>>  T.Add(TApple.Create());
>>  T.Add(TOrange.Create());
>>  // Whoops, what was that? Now our program might crash.
>>end;
>>
>>Of course, we could create a specialized TAppleList that only accepts Apples,
>>but that's boring and hard work. A much cleaner way is generics:
>>
>>var
>>  T: TList<TApple>;
>>begin
>>  T := TList<TApple>.Create();
>>  T.Add(TApple.Create());
>>  T.Add(TOrange.Create());
>>  // This wont compile! The problem is prevented at compile-time!
>>end;
>>
>>I hope that answers your question as to why it's a good idea :-)
>>
>>--
>>Regards,
>>Christian Iversen
> 
> 
> 
> Sort of, but I don't see why people use TApple and TOrange examples all the time ;-) I mean
> when was the last time you actually programmed a software application that was organizing
> Apples and Oranges? I use things like strings, databases, integers, FTP, CGI, stringlists,
> etc. Sure apples and oranges can represent a sort of metaphor for ANYTHING, but I'd prefer
> just to cut straight to the real world example instead.

I assume that when ever you wrote some piece of software you needed a 
list of something, say a list of integers and a list of objects.
(at least I need them a lot)

you can solve this in various ways.

1) -------------------
you can use an instance of TList and use a lot of casting. I guess you 
understand this is pretty unsafe. It requires a lot of dicipline from 
you as programmer (and from your co coders)

example 1a (objects in a list):

list := TList.Create;
obj := TMyObject.Create;
list.add(obj);
obj := TMyObject.Create;
list.add(obj);

if you need an object form yuor list, you need
obj := TObject(List[1]); //unsafe cast.

example 1b (integers in a list):

list := TList.Create;
list.add(Pointer(someint));    //typecast needed to add
list.add(Pointer(anotherint));

if you need an integer form yuor list, you need
yourint := Integer(List[1]); //unsafe cast.


2) -------------------
To make things safer, you can create dedicated classes for them with 
TList as base class. Since you need specific tipes, you need to override 
all methods where TList uses a pointer.
This means write a wrapper for Add, Insert, IndexOf, Get, Set, etc. This 
means a lot of coding

TMyIntList.Add(value: Integer)
begin
   inherited Add (Pointer(Value));
end;

etc.

3) -------------------

Use generics.
Now you code your TList<T> once like (I assume some syntax here)

type
   TList<_T> is class(TObject)
     procedure Add(item: _T);
     ....
   end;

Now, when you need a list of intgers, you can declare it as

type
   TMyIntList = TList<integer>;
...

list := TMyIntList.Create;
list.Add(someInt);

or even when you need a list of TSomeObject:

type
   TMySomeObjectList = TList<TSomeObject>;
...

list := TMySomeObjectList.Create;
obj := TSomeObject.Create;
list.Add(obj);

-------
You understand now ? I only defined/coded one generic list class, and I 
can use it to store all kinds of types in a typesafe manner.
The advantage is that I can reuse the (in this case) list code, so I 
only have to solve problems in one place, it reduces time, since I don't 
have to copy/paste/find/replace existing classes etc.


> I guess the real world examples are hard to display unless you have actually used generics
> in a software program, and you are willing to offer code snippets from the program.

I cannot give you a real world generic example, since it doesn't exist 
yet for delphi. And thats where I write programs with. And yes, I've 
coded several similar list with all different types.

Marc





More information about the fpc-devel mailing list