Die Inferenz vom Hindley-Milner-Typ wird für Systeme vom Hindley-Milner-Typ verwendet, eine Einschränkung von Systemen vom System-F-Typ. Das interessante Merkmal von HM-Typ-Systemen ist, dass sie einen parametrischen Polymorphismus (auch bekannt als Generika) haben. Dies ist das größte Systemmerkmal, das Golang ablehnt.
Mit dieser frustrierenden Einschränkung ist eine Inferenz im HM-Stil unmöglich. Schauen wir uns den untypisierten Code an:
func f(a) {
return a.method()
}
Was ist die Art von f
? Wir können feststellen , dass a
muss eine Methode haben, so konnten wir eine anonyme Schnittstelle benutzen func f(a interface { method() ??? }) ???
. Wir haben jedoch keine Ahnung, was der Rückgabetyp ist. Mit Typvariablen können wir den Typ als deklarieren
func f[T](a interface{ method() T }) T
Da Go jedoch keine Typvariablen hat, funktioniert dies nicht. Während implizite Interfaces einige Aspekte der Typinferenz vereinfachen, können wir den Rückgabetyp eines Funktionsaufrufs jetzt nicht herausfinden. Das HM-System erfordert, dass alle Funktionen deklariert und nicht impliziert werden, und jeder Name kann nur einen einzigen Typ haben (wohingegen Go-Methoden unterschiedliche Typen in unterschiedlichen Schnittstellen haben können).
Stattdessen erfordert Go, dass Funktionen immer vollständig deklariert sind, Variablen jedoch die Verwendung von Typinferenz ermöglichen. Dies ist möglich, weil die rechte Seite einer Zuweisung variable := expression
zu diesem Zeitpunkt des Programms bereits einen bekannten Typ hat. Diese Art der Typinferenz ist einfach, korrekt und linear.
- Der Typ einer Variablen ist zum Zeitpunkt der Deklaration sofort bekannt, wohingegen HM-Inferenz möglicherweise zuerst das gesamte Programm typüberprüfen muss. Dies wirkt sich auch spürbar auf die Qualität der Fehlermeldungen aus.
- Der Typinferenzansatz von Go wählt immer den spezifischsten Typ für eine Variable aus, im Gegensatz zu HM, das den allgemeinsten Typ auswählt. Dies funktioniert auch bei impliziten Go-Schnittstellen problemlos mit Subtyping.