Perché Java non esegue l'inferenza del tipo?

43

Mi sono sempre chiesto perché Java non faccia tipo di inferenza dato che il linguaggio è quello che è, e la sua VM è molto matura. Google's Go è un esempio di linguaggio con inferenza di tipo eccellente e riduce la quantità di digitazione che si deve fare. C'è qualche motivo particolare per cui questa funzione non fa parte di Java?

    
posta cobie 19.01.2013 - 00:36
fonte

5 risposte

59

Tecnicamente parlando, Java ha tipo di inferenza quando si usano i generici. Con un metodo generico come

public <T> T foo(T t) {
  return t;
}

Il compilatore analizzerà e capirà che quando scrivi

// String
foo("bar");
// Integer
foo(new Integer(42));

Una stringa verrà restituita per la prima chiamata e un intero per la seconda chiamata in base a ciò che è stato inserito come argomento. Come risultato otterrai il corretto controllo in fase di compilazione. Inoltre, in Java 7, si può ottenere qualche inferenza di tipo aggiuntivo quando istanziazione di generici come tale

Map<String, String> foo = new HashMap<>();

Java è abbastanza gentile da riempire le parentesi angolari vuote per noi. Ora, perché Java non supporta il tipo di inferenza come parte dell'assegnazione delle variabili? A un certo punto, c'era un RFE per l'inferenza del tipo nelle dichiarazioni variabili, ma questo era chiuso come "Non risolverà" perché

Humans benefit from the redundancy of the type declaration in two ways. First, the redundant type serves as valuable documentation - readers do not have to search for the declaration of getMap() to find out what type it returns. Second, the redundancy allows the programmer to declare the intended type, and thereby benefit from a cross check performed by the compiler.

Il contributore che ha chiuso questo ha anche notato che si sente semplicemente "un-java-like", con il quale sono d'accordo. La verbosità di Java può essere sia una benedizione che una maledizione, ma rende il linguaggio quello che è.

Ovviamente quella particolare RFE non era la fine di quella conversazione. Durante Java 7, questa funzione era nuovamente considerata , con alcune implementazioni di test in fase di creazione, tra cui uno di James Gosling stesso. Ancora una volta, questa funzione è stata in ultima analisi abbattuta.

Con il rilascio di Java 8, ora otteniamo l'inferenza di tipo come parte di lambda in quanto tale:

List<String> names = Arrays.asList("Tom", "Dick", "Harry");
Collections.sort(names, (first, second) -> first.compareTo(second));

Il compilatore Java è in grado di esaminare il metodo Collections#sort(List<T>, Comparator<? super T>) e quindi l'interfaccia di Comparator#compare(T o1, T o2) e determina che first e second dovrebbero essere un String , consentendo così al programmatore di rinunciare a dover rideterminare il tipo nell'espressione lambda.

    
risposta data 19.01.2013 - 04:51
fonte
15

Beh, per prima cosa, l'inferenza di tipo ha nulla da fare con la maturità del runtime, sia che il runtime sia una CPU di 30 anni o una VM così nuova i bit siano ancora brillanti. è tutto per il compilatore.

Detto questo, è consentito per i generici, il motivo per cui non è consentito per i tipi non generici sembra essere dovuto alla filosofia - non c'è nulla che impedisca ai designer di aggiungerlo.

Aggiornamento: sembra che java 10 lo supporti - link

    
risposta data 19.01.2013 - 05:45
fonte
5

Per quanto ne so, quando Java è stato progettato all'inizio degli anni '90 l'inferenza di tipo non era così popolare tra le lingue tradizionali (ma era già un concetto molto noto, ad esempio in ML). Quindi, posso immaginare che l'inferenza di tipo non fosse probabilmente supportata perché Java era rivolto a programmatori provenienti da C ++, Pascal o altri linguaggi mainstream che non ne avevano (principio di minima sorpresa).

Inoltre, uno dei principi di progettazione di Java è quello di scrivere le cose in modo esplicito per assicurarsi che il programmatore e il compilatore abbiano la stessa comprensione del codice: la duplicazione delle informazioni riduce le possibilità di errori. Certo, può essere una questione di gusti se scrivere qualche altro personaggio vale la sicurezza extra che fornisce, ma questa è stata la filosofia di design seguita per Java: scrivere le cose in modo esplicito.

Non so se Java otterrà inferenza di tipo in futuro ma IMO sarebbe una grande rivoluzione per la lingua (come ha detto Glenn Nelson, è stato descritto come "un-java-like") e quindi si potrebbe anche considera di abbandonare il nome Java in favore di un nuovo nome.

Se vuoi usare una lingua JVM con inferenza di tipo puoi usare Scala.

    
risposta data 19.01.2013 - 11:54
fonte
2

Posso pensare ad alcuni possibili motivi. Uno è che la tipizzazione esplicita è auto-documentante. Java generalmente lo rende una priorità rispetto alla concisione. Un altro motivo potrebbe essere nei casi in cui il tipo è alquanto ambiguo. Come quando un tipo o qualsiasi sottotipo potrebbe soddisfare una routine. Diciamo che vuoi usare una lista, ma qualcuno arriva e usa un metodo esclusivo per ArrayList. Il JIT inferirebbe una ArrayList e proseguirà anche se volessi un errore di compilazione.

    
risposta data 19.01.2013 - 04:56
fonte
0

È in contraddizione con la raccomandazione consolidata di dichiarare le variabili usando l'interfaccia più generica che si adatta alle tue esigenze e inizializzarle con una classe di implementazione appropriata, come in

Collection<String> names = new ArrayList<>();

Effettivamente,

var names = new ArrayList<String>();

non è altro che zucchero sintattico per

ArrayList<String> names = new ArrayList<String>();

Se lo desideri, il tuo IDE può produrlo dall'espressione new ArrayList<String>() con "un clic" (refactor / create local variable), ma ricorda che contraddice il consiglio "use interfaces".

    
risposta data 23.09.2018 - 21:27
fonte

Leggi altre domande sui tag