Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi generic nested classes

I was doing a comparison between C++ and Delphi and I found something tricky to me.

This is very easy C++ code:

template<typename T>
class C {

 class D {
  T x;
 }

}

In this scenario, we have that the class C is a template class ( = generic class) and the nested class D is also a template class. If T is a double, the x inside D is double.

I cannot say this:

template<typename T>
class C {

 template<typename T>
 class D {
  T x;
 }

}

That is an error since I am already "inside" C and another T would be a conflict. To fix the error, I should use a different name, like U.

template<typename T>
class C {

 template<typename U>
 class D {
  T x;
 }

}

In Delphi, I could write this:

type
 TClassC<T> = class
  private

   type
    TClassD = class
     private 
      x: T;
    end;

 end;

If T is an integer, now x is an integer since (from what I've understood reading online) the TClassD is integer. In Delphi this is also legal:

type
 TClassC<T> = class
  private

   type
    TClassD<T> = class // <-- note the <T> repeated!!
     private 
      x: T;
    end;

 end;

What about now? If I am able to declare T again in TClassD, this means that without the <T> I'd have a non-generic TClassD class. Am I correct?

like image 593
Raffaele Rossi Avatar asked Nov 07 '17 20:11

Raffaele Rossi


1 Answers

Consider this simple program:

type
  TClassC<T> = class
  private
    type
    TClassD<T> = class
    private
      x: T;
    end;
  end;

var
  obj: TClassC<Integer>.TClassD<string>;

begin
  obj := TClassC<Integer>.TClassD<string>.Create;
  obj.x := 42;
end.

This program compiles, but emits the following hint:

[dcc32 Hint]: H2509 Identifier 'T' conflicts with type parameters of container type

The assignment proves that x takes its type from the outer generic parameter rather than the inner.

I have to say that this surprised me because I was expecting the opposite. I was expecting that the inner generic parameter would hide the outer. In fact, so far as I can tell, there is no way for the inner type to refer to its generic parameter.

In order to be able to refer to both generic parameters you would need to use different names for them. For instance:

type
  TClassC<T1> = class
  private
    type
    TClassD<T2> = class
    private
      x: T2;
    end;
  end;

This is what the analagous C++ template code forces you to do.

In my view, it is a design weakness of the Delphi language that you are permitted to compile the code at the top of this answer.

like image 138
David Heffernan Avatar answered Oct 16 '22 16:10

David Heffernan