2010-04-25 4 views
5

Tenir compte de la déclaration suivante d'une classe utilitaire générique Delphi 2010:Pourquoi Delphi ne peut-il pas déduire le type d'un paramètre TEnumerable <T>?

TEnumerableUtils = class 
public 
    class function InferenceTest<T>(Param: T): T; 
    class function Count<T>(Enumerable: TEnumerable<T>): Integer; overload; 
    class function Count<T>(Enumerable: TEnumerable<T>; Filter: TPredicate<T>): Integer; overload; 
end; 

D'une certaine façon l'inférence de type de compilateur semble avoir des problèmes ici:

var 
    I: Integer; 
    L: TList<Integer>; 
begin 
    TEnumerableUtils.InferenceTest(I); // no problem here 
    TEnumerableUtils.Count(L);   // does not compile: E2250 There is no overloaded version of 'Count' that can be called with these arguments 
    TEnumerableUtils.Count<Integer>(L); // compiles fine 
end; 

Le premier fonctionne appel comme prévu et T est correctement inféré comme Entier.

Le deuxième appel ne fonctionne pas, sauf si j'ajoute également <Integer> - alors cela fonctionne, comme on peut le voir dans le troisième appel. Est-ce que je fais quelque chose de mal ou est l'inférence de type dans Delphi ne supporte pas cela (je ne pense pas que ce soit un problème en Java qui est la raison pour laquelle il devrait fonctionner en Delphi, aussi).

Répondre

9

Le compilateur doit effectuer une correspondance de modèle pour déduire les types de paramètres; ce n'est pas le cas actuellement. Le compilateur est limité à une inférence assez simple - si le type de paramètre est d'un type de type type, alors le compilateur peut le comprendre, mais pas beaucoup plus loin que cela. Dans votre exemple, le type d'argument n'est pas un simple paramètre de type, mais plutôt un type générique construit (construit avec le paramètre de type T de la méthode, mais il n'en est pas moins construit). Le compilateur doit faire deux inférences pour trouver la valeur de T. D'abord, il doit voir que le type générique du type construit est un ancêtre du type générique de TList<T>; et il doit également faire correspondre le paramètre de type T dans la liste des paramètres de type du type construit avec le type concret Integer dans l'ancêtre TList<T>.

+1

Dans ce cas, serait-il trop dur de dire que l'implémentation d'inférence de type Delphi est à peine suffisante pour justifier son inclusion dans la boîte en tant que "nouvelle fonctionnalité", mais pas vraiment suffisante pour être considérée comme significative? Achevée" ? – Deltics

+1

Parfois, «juste assez bon» n'est vraiment pas bon du tout - mieux vaut ne pas avoir quelque chose que d'avoir quelque chose qui ne peut pas chahuter, ne se dandine pas et ne peut que nager mais jamais le moins s'appelle un "canard". "Mieux" dans le sens où cela ne conduirait pas alors à ce genre de question/confusion qui attire l'attention sur le "trou de la fonctionnalité" et donnant des munitions à ceux qui cherchent à rejeter Delphi comme has-been/aussi couru. Mieux vaut dire: "l'inférence de type ne s'installe pas confortablement avec la nature de Pascal" - qui est, à mon avis, une position parfaitement vraie et valide. – Deltics

+0

Merci, Barry. Il semble que je doive vivre avec alors. Peut-être l'année prochaine ... ;-) Une petite question connexe si je peux: dois-je baser cette classe utils sur IEnumerable au lieu de TEnumerable? Semble être plus général pour moi, et l'aide déclare que IEnumerable ne doit pas être déclaré sur les classes qui ont une méthode GetEnumerator. –

Questions connexes