Delphi Type-Inference in Generic Methods

FireWind

Свой
Регистрация
2 Дек 2005
Сообщения
1,957
Реакции
1,199
Credits
4,009
Type-Inference in Generic Methods
17. February 2021 by Olaf Monien

Due to an interesting code example, behind which Для просмотра ссылки Войди или Зарегистрируйся first suspected a possible bug in the Delphi compiler, I took a closer look at the calling behavior of overloaded methods that also contain generic type parameters. I was surprised by the possible bug since I use overloads with combinations of generic and non-generic methods in current projects without any obvious errors.

Here is a simplified version of Kim’s code:
Код:
TFoo = class(TObject)
  public
    function DoSomething(SomeObject: TValue): string; overload;
    function DoSomething<T>(SomeObject: T): string; overload;
  end;
 
TBar = class(TObject)
end;
 
//...
 
var Foo := TFoo.Create;
var Bar := TBar.Create;
 
Foo.DoSomething(Bar);
Which of the two possible variants of DoSomething should be called by Foo.DoSomething(Bar)?

At a first glance, I was inclined to say that the non-generic variant, i.e. function DoSomething(SomeObject: TValue): string; should be called, since after all no type parameter is specified and therefore the first variant matches best.

But in fact, the generic, second variant is called. I initially suspected “TValue” of “blocking” the overload resolution here, since TValue is actually an “artificial” RTTI.driven type.

Для просмотра ссылки Войди или Зарегистрируйся came up with the correct hint:

Generic parameters are actually optional and the type is automatically inferred by the type of the variable that is passed. This “type inference” takes precedence over overload resolution and thus produces a better match than the “TValue” method.

Type-inference of generic methods Для просмотра ссылки Войди или Зарегистрируйся btw.

So the following code actually calls a generic implementation, although no type parameter is specified in the call:
Код:
function DoSomething<T>(SomeObject: T): string;
//...
Foo.DoSomething(Bar); //<T> is inferred from "Bar"
Here is a Gist with full code to try:

Для просмотра ссылки Войди или Зарегистрируйся