2010-04-25 14 views
5

Si consideri la seguente dichiarazione di una classe di utilità generica in Delphi 2010:Perché Delphi non è in grado di inferire il tipo per un parametro 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; 

In qualche modo il tipo di compilatore di inferenza sembra avere problemi qui:

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; 

La prima chiamata funziona come previsto e T è correttamente dedotto come numero intero.

La seconda chiamata non funziona, a meno che non aggiunga anche <Integer> - quindi funziona, come si può vedere nella terza chiamata. Sto facendo qualcosa di sbagliato o l'inferenza di tipo in Delphi non lo supporta (non penso che sia un problema in Java, motivo per cui mi aspetto che funzioni anche in Delphi).

risposta

9

Il compilatore deve eseguire la corrispondenza del modello per inferire i tipi di parametri; al momento non lo fa. Il compilatore è limitato a inferenza abbastanza semplice - se il tipo di parametro è di tipo type, il compilatore può capirlo, ma non molto oltre.

Il tipo di argomento nell'esempio non è un parametro di tipo semplice, ma è piuttosto un tipo generico costruito (è costruito con il parametro di tipo T del metodo, ma è comunque costruito). Il compilatore deve fare due inferenze per scoprire il valore di T. Innanzitutto, deve vedere che il tipo generico del tipo costruito è un antenato del tipo generico di TList<T>; e deve anche corrispondere al parametro di tipo T nella lista dei parametri di tipo del tipo costruito con il tipo concreto Intero nell'antenato di TList<T>.

+1

In questo caso, sarebbe troppo duro dire che l'implementazione di tipo Delphi che deduce l'inferenza è appena abbastanza buona da giustificare l'inclusione sul box come una "nuova funzionalità", ma non abbastanza buona per essere considerata significativamente " completare" ? – Deltics

+1

A volte "solo abbastanza bene" non è abbastanza buono - meglio non avere qualcosa per niente che avere qualcosa che non può smettere di fumare, non va in giro e può nuotare a malapena, ma va sempre in giro chiamandosi "anatra". "Meglio" nel senso che non porterebbe poi a questo tipo di domande/confusione che attira l'attenzione sul "divario di caratteristiche" e che fornisce munizioni a coloro che cercano di licenziare Delphi come una persona che è stata/ha anche corso. Meglio dire: "il tipo di inferenza non si adatta confortevolmente alla natura di Pascal" - che è, imho, una posizione perfettamente vera e valida. – Deltics

+0

Grazie, Barry. Sembra che devo conviverci allora. Forse l'anno prossimo ... ;-) Una piccola domanda correlata se posso: dovrei basare questa classe di utils su IEnumerable invece di TEnumerable? Sembra essere più generale per me, e l'aiuto afferma che IEnumerable non deve essere dichiarato su classi che hanno un metodo GetEnumerator. –

Problemi correlati