views:

707

answers:

2
   TMyDataList<T: TBaseDatafile, constructor> = class(TObjectList<TBaseDatafile>)
   public
      constructor Create;
      procedure upload(db: TDataSet);
   end;

I read in a blog post (I don't remember where now) that this is the way to declare a generic-based class with a specific base type for the generic object. And the compiler will accept it just fine. But when I try to use it, it decides not to cooperate.

type
   TDescendantList = TMyDataList<TDescendantDatafile>;

This gives me a compiler error.

[DCC Error] my_database.pas(1145): E2010 Incompatible types: 'TDescendantDatafile' and 'TBaseDatafile'

Thing is, 1145 isn't even a valid line. The file in question ends at #1142, and the type declaration that it's complaining about is on line #20. This makes me wonder if it's a compiler glitch. Or do I just not quite have the syntax right? Does anyone know a way to make this work?

EDIT: Jim pointed out that it compiles fine when he tried it. A bit more information: I have the base datafile type and the generic list declared in the same unit, while TDescendantDatafile is in a second unit and TDescendantList is defined in a third one. I've already found and reported one bug in D2009's compiler involving generics screwing up types across multiple units. This may be related. Can anyone confirm this?

+2  A: 

The definition of TObjectList<> is:

TObjectList<T: class> = class(TList<T>)

So you like to do something like:

TMyDataList<T: TBaseDatafile> = class(TObjectList<T>)

Unfortunately, that won't work. Luckily:

TMyDataList<T: class> = class(TObjectList<T>)

Works, but that is probably not what you want. Because it will not take advantage of the class type. I really think the class specifier is a bit strange here. (TObject should have avoided the problems). But that's no help for you.

Then again, the following works:

  TBaseDataFile = class
  end;

  TDescendantDatafile = class (TBaseDataFile)
  end;

  TMyDataList<T: TBaseDataFile> = class(TObjectList<TBaseDataFile>)
  public
    constructor Create;
  end;

Are you sure TDescendantDataFile inherits from TBaseDataFile?

In the old days, (read turbo pascal) sometimes the line numbers where wrong because of invisible characters. But I don't think that is still valid.

Gamecat
Your "working" example is almost exactly how I've got it set up. Problem is, I can't create any actual instances of the list with the type filled in. (And yes, I'm quite sure of the inheritance.)
Mason Wheeler
If it is "almost" exactly like you have it set up, then make it exactly like it and see if that works.
Jim McKeeth
+1  A: 

When TDescendantDatafile descends from TBaseDataFile it works fine on my machine. Check your class hierarchy.

If I change the ancestor of TDescendantDatafile then I get that same error message, and it gives my the right line numbers. If you the compiler is giving you the wrong line numbers then close the project, reopen it and do a full build.

Jim McKeeth
The hierarchy is correct. Restarting and rebuilding didn't help. Hmm... try this: declare TMyDataList and TBaseDatafile in one unit, TDescendantDatafile in another, and TDescendantList in a third. I've already found one bug with Generics and multiple units. This could possibly be another one.
Mason Wheeler