Recent

Author Topic: How to inherit from a Generic class  (Read 23386 times)

Amir61

  • New Member
  • *
  • Posts: 41
    • http://Amir.Aavani.net
How to inherit from a Generic class
« on: July 21, 2010, 07:43:30 am »
I want to implement a generic class,TB, which inherits from another generic class, TA, something like the following:

generic TA<T>= class (TObject)
end;

generic TB<T>= class (TA<T>)
end;

But it does not work! Any idea how I can do that.

bflm

  • Jr. Member
  • **
  • Posts: 54
    • Free Pascal Random Bits
Re: How to inherit from a Generic class
« Reply #1 on: July 21, 2010, 12:47:00 pm »
I want to implement a generic class,TB, which inherits from another generic class, TA, something like the following:

generic TA<T>= class (TObject)
end;

generic TB<T>= class (TA<T>)
end;

But it does not work! Any idea how I can do that.

It's documented:

http://www.freepascal.org/docs-html/ref/refse43.html

In short, class type you're extending has to be concrete. Already specialized generic class type is concrete and can be extended/inherited from.

Leledumbo

  • Hero Member
  • *****
  • Posts: 8799
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: How to inherit from a Generic class
« Reply #2 on: July 21, 2010, 01:00:31 pm »
note also FPC generics status is still experimental, such construct might or might not be supported in the future. On the other hand, I don't see any alternative to declare such construct using current FPC generics implementation since the generic parameter is given by descendant classes.

Amir61

  • New Member
  • *
  • Posts: 41
    • http://Amir.Aavani.net
Re: How to inherit from a Generic class
« Reply #3 on: July 25, 2010, 12:10:45 am »
If I got you correctly, you are saying it is impossible to have such structure using inheritance.

I guess such structures can be implemented using interfaces (But I was trying to avoid that).




eny

  • Hero Member
  • *****
  • Posts: 1646
Re: How to inherit from a Generic class
« Reply #4 on: July 25, 2010, 01:38:33 pm »
Code: [Select]
  generic TA<A> = class(TOBject)
  end;

  _TA = specialize TA<TObject>;

  generic TB<B> = class(_TA)
  end;
All posts based on: Win10 (Win64); Lazarus 3_4  (x64) 25-05-2024 (unless specified otherwise...)

Amir61

  • New Member
  • *
  • Posts: 41
    • http://Amir.Aavani.net
Re: How to inherit from a Generic class
« Reply #5 on: July 25, 2010, 07:19:37 pm »
No, this does not work. For example consider the case where type B to be an integer (not TObject)

eny

  • Hero Member
  • *****
  • Posts: 1646
Re: How to inherit from a Generic class
« Reply #6 on: July 25, 2010, 09:32:54 pm »
Sure this works; we're talking classes, not primitive types!

Nevertheless, it all depends on the problem you're trying to solve.
What you're trying to do looks a bit like multiple inheritance.
Is that what you need?
All posts based on: Win10 (Win64); Lazarus 3_4  (x64) 25-05-2024 (unless specified otherwise...)

Amir61

  • New Member
  • *
  • Posts: 41
    • http://Amir.Aavani.net
Re: How to inherit from a Generic class
« Reply #7 on: July 26, 2010, 02:13:54 am »
I guess not :D

I want to have a generic TAbtractQueue class and two generic classes TGenericQueue and TGenericCircularQueue such that each of them implements TAbstractQueue.

generic TAbstractQueue<T>= class (TObject)
  public:
    procedure Insert (Data:  T); abstract;
    function Delete:  T; abstract;
 ....

end;

Your approach does not work because T can be an object or a primitive type.



eny

  • Hero Member
  • *****
  • Posts: 1646
Re: How to inherit from a Generic class
« Reply #8 on: July 26, 2010, 06:29:39 pm »
You're making it too complicated.
Just define TAbstractQueue as a 'regular' abstract base class and let TGenericQueue  and TGenericCircularQueue  inherit from that abstract base class. Just use TObject as data types for the parameters.

If you need classtype-specific behaviour, you can make TGenericQueue and TGenericCircularQueue  generic, but based on TAbstractQueue (which is a abstract class, not a 'generic base class') and not on TObject.

Code: [Select]
TAbstractQueue = class(TObject)
  procedure insert (Data: TObject); virtual; abstract;
end;

generic TGenericQueue<Q> = class(TAbstractQueue)
  // Overridden from base class
  procedure insert(Data: TObject); override;

  // generic-specific procs..

end;

'Generics are templates for generating classes'... so mixing primitive types and classes is not gonna happen (at least according to the docs  8)).
« Last Edit: July 26, 2010, 06:33:42 pm by eny »
All posts based on: Win10 (Win64); Lazarus 3_4  (x64) 25-05-2024 (unless specified otherwise...)

Amir61

  • New Member
  • *
  • Posts: 41
    • http://Amir.Aavani.net
Re: How to inherit from a Generic class
« Reply #9 on: July 28, 2010, 12:00:49 am »
I thought about this approach, too but then  using the queue class is not very easy :(

Assume I want to have a GenericQueue  whose elements are Double and store the Queue object in an AbstractQueue Object.

Then, to insert a new value into the queue I need to write:

Code: [Select]
type
  TDoubleQueue= specialize TGenericQueue<Double>;
...
...

var
  Q: TAbstractQueue;
   DPtr: PDouble;

begin
  ...
  Q:= TDoubleQueue.Create;
  ....
  New (DPtr);
  Dptr^:= 1.2;
  Q.Insert (TObject (DPtr));
  ...

end;

That is, for any insertion I need to allocate a some memory and I need to keep track of memory allocation and ... .

eny

  • Hero Member
  • *****
  • Posts: 1646
Re: How to inherit from a Generic class
« Reply #10 on: July 28, 2010, 02:22:07 pm »
As I said before: don't mix primitive types and class types.
For how many primitive types do you want to use your queues?

However, what you can do: create a DoubleFactory class that does all 'pointer magic' for you. The queue class calls the DoubleFactory every time it needs a new floating point pointer. If you need integers, you create a IntegerFactory.
Use dependency injection to make your queue aware of the <type>factory it must use.

Also: if you use classes you can define a function in the generic base class, that instantiates a new object for you.
All posts based on: Win10 (Win64); Lazarus 3_4  (x64) 25-05-2024 (unless specified otherwise...)

Chronos

  • Sr. Member
  • ****
  • Posts: 250
    • PascalClassLibrary
Re: How to inherit from a Generic class
« Reply #11 on: July 28, 2010, 04:03:46 pm »
Generic class inheritance is if fact necessary to build good general classes.

For example could need common TList similar to array costruction. Definition of array is composed from index type and item type so generic TList should look like:
Code: [Select]
TList<TIndexType, TItemType> = class
private
  Items: array[TIndexType] of TItemType;
  ...
public
  methods...
  properties...
end;
Than some specialised types could be defined as:
Code: [Select]
TByteList = TList<Integer, Byte>
TStringList = TList<Integer, string>
TObjectList = TList<Integer, TObject>

Index range could be scaled to:
Code: [Select]
TShortStringList = TList<ShortInt, string>
TSmallStringList = TList<Small, string>
TLongStringList = TList<LongInt, string>
THugeStringList = TList<Int64, string>
TCustomSizeStringList = TList<0..10, string>
TColorStringList = TList<TColor, string>

But in Delphi index type require ordinal type so it can't be fully general class. Maybe it could be solved using some type constrains.


Next requirements is inheritance...

Code: [Select]
TList<TIndexType,TItemType> = class
  Items: Pointer;
  Size: TIndexType;
  ...
end;

TOrderedList<TIndexType,TItemType> = class
end

TIntegerList<TIndexType> = class(TList<TIndexType, Integer>);

TCapacityGenericList<TIndexType,TItemType> = class(TList<TIndexType,TItemType>)
  Capacity: TIndexType; // Less realocations
  ...
end;

TStack<TIndexType,TItemType> = class(TList<TIndexType,TItemType>)
  procedure Push(Item: TItemType);
  function Pop: TItemType;
end;

TQueue<TIndexType,TItemType> = class(TList<TIndexType,TItemType>)
  procedure Push(Item: TItemType);
  function Pop: TItemType;
end;

TMyGenericQueue<TIndexType,TItemType> = class(TQueue<TIndexType,TItemType>)
  ...
end;

So to build wide usable common classes we need inheritance as well.

But in FPC similar constructs not work.

Code: [Select]
generic TList<TItemType> = class
end;

generic TMyList<TItemType> = class(TList); // Error: Generics without specialization can not be used as a type for a variable
generic TMyList<TItemType> = class(TList<TItemType>); // Error: Generics without specialization can not be used as a type for a variable
generic TMyList<TItemType> = class(generic TList<TItemType>); // Error: Identifier not found "generic"
generic TMyList<TItemType> = class(specialize TList<TItemType>); // Error: Identifier not found "TItemType"




eny

  • Hero Member
  • *****
  • Posts: 1646
Re: How to inherit from a Generic class
« Reply #12 on: July 28, 2010, 04:36:54 pm »
It's better to focus on what you wish to accomplish instead of going to the how too quickly.
IMHO there is no need for this kind of fuzzy template functionality.
All posts based on: Win10 (Win64); Lazarus 3_4  (x64) 25-05-2024 (unless specified otherwise...)

Amir61

  • New Member
  • *
  • Posts: 41
    • http://Amir.Aavani.net
Re: How to inherit from a Generic class
« Reply #13 on: July 28, 2010, 07:38:46 pm »
eny: I hope you saw the problem.
The question is not "For how many primitive types do you want to use your queues?". The whole point of allowing generic classes is to avoid developing(copying and pasting) the same code several times. As "chronos"  described, sometimes it is much easier (and makes more sense) to inherit from a generic class (similar to C++ templates).


eny

  • Hero Member
  • *****
  • Posts: 1646
Re: How to inherit from a Generic class
« Reply #14 on: July 28, 2010, 08:35:43 pm »
eny: I hope you saw the problem.
No worries  :D

My point is: understand the actual problem you're trying to solve and model your solution with the tools you've chosen.
Lazarus'/FP's limitations are not part of the problem.
All posts based on: Win10 (Win64); Lazarus 3_4  (x64) 25-05-2024 (unless specified otherwise...)

 

TinyPortal © 2005-2018