Alois Heimer
Alois Heimer

Reputation: 1832

"Nested" type constraints in Delphi

Suppose I have a class

TController<T_Ui: TGui; T_Man: TManager> = class
end;

If I try to use this class as a constraint for a generic procedure like this:

procedure MyProc<T: TController<T_Ui, T_Man>>(ACont: T);

I get an error undefined identifier T_Ui.


Is there a shorter way to define the procedure than

procedure MyProc<T_Ui: TGui; TMan: TManager; T: TController<T_Ui, T_Man>>(ACont: T);

if all that I want is constraint T to the TController type?

Edited:

If I could define:

procedure MyProc<T: TController<*, *>>(ACont: T);

everything should be clear for the compiler.

My problem is, that instead of writing

MyProc<TMyController>(Cont);

I need to write

MyProc<TMyUi, TMyManager, TMyController>(Cont);

Upvotes: 3

Views: 369

Answers (1)

David Heffernan
David Heffernan

Reputation: 613461

procedure MyProc<T: TController<T_Ui, T_Man>>(ACont: T);

Let's consider what this means. This is a generic method with one generic parameter T which is a class that must derive from TController<T_Ui, T_Man>. Since T_Ui and T_Man are not generic parameters, the compiler has to interpret them as concrete types. You did not define types of that name, hence the compiler error.

But of course you don't want the compiler to treat T_Ui and T_Man as concrete types. You mean them to be generic parameters. In which case you have to declare them as such.

procedure MyProc<T_Ui: TGui; TMan: TManager; T: TController<T_Ui, T_Man>>(ACont: T);

Or perhaps like this.

procedure MyProc<T_Ui: TGui; TMan: TManager>(ACont: TController<T_Ui, T_Man>);

Which is simpler by way of removing the redundant parameter T.

In essence you are hoping for an implicit parametrization but that does not exist. Generic parameters must be declared explicitly.

Now, one technique that is sometimes used is to declare a non-generic class as the base type for your generic class.

type
  TController = class
    ....
  end;

  TController<T_Ui: TGui; T_Man: TManager> = class(TController)
    ....
  end;

Then you can write your generic method like this:

procedure MyProc<T: TController>(ACont: T);

Now, this approach requires that you can declare sufficient functionality in TController. If MyProc needs to call methods that can only be declared in a generic class derived from TController, then this approach is of no use to you.

Upvotes: 2

Related Questions