Il semble que tous les nouveaux langages de programmation ou du moins ceux qui sont devenus populaires utilisent l'inférence de type. Même Javascript a obtenu des types et des inférences de types via diverses implémentations (Acscript, typescript, etc.). Cela me semble bien, mais je me demande s'il y a des compromis ou pourquoi disons que Java ou les anciens bons langages n'ont pas d'inférence de type
- Lorsque vous déclarez une variable dans Go sans spécifier son type (en utilisant var sans type ou la syntaxe: =), le type de la variable est déduit de la valeur sur le côté droit.
- D permet d'écrire de gros fragments de code sans spécifier de types redondants, comme le font les langages dynamiques. D'autre part, l'inférence statique déduit des types et d'autres propriétés de code, donnant le meilleur des mondes statique et dynamique.
- Le moteur d'inférence de type dans Rust est assez intelligent. Il fait plus que regarder le type de la valeur r lors d'une initialisation. Il examine également comment la variable est utilisée par la suite pour déduire son type.
- Swift utilise l'inférence de type pour déterminer le type approprié. L'inférence de type permet à un compilateur de déduire automatiquement le type d'une expression particulière lorsqu'il compile votre code, simplement en examinant les valeurs que vous fournissez.
programming-languages
type-systems
L'utilisateur sans chapeau
la source
la source
var
car cela peut parfois nuire à la lisibilité.var
et C ++auto
) et l' inférence de type (bidirectionnelle, comme Haskelllet
). Dans le premier cas, le type d'un nom peut être déduit uniquement de son initialiseur - ses utilisations doivent suivre le type du nom. Dans ce dernier cas, le type d'un nom peut également être déduit de ses utilisations, ce qui est utile en ce que vous pouvez écrire simplement[]
pour une séquence vide, quel que soit le type d'élément, ounewEmptyMVar
pour une nouvelle référence mutable nulle, quel que soit le référent type.Réponses:
Le système de types de Haskell est entièrement déductible (en laissant de côté la récursion polymorphe, certaines extensions de langage et la restriction redoutée du monomorphisme ), mais les programmeurs fournissent encore fréquemment des annotations de type dans le code source même lorsqu'ils n'en ont pas besoin. Pourquoi?
map :: (a -> b) -> [a] -> [b]
. Sa forme plus générale (fmap :: Functor f => (a -> b) -> f a -> f b
) s'applique à tous lesFunctor
s, pas seulement aux listes. Mais il a été estimé que cemap
serait plus facile à comprendre pour les débutants, alors il vit aux côtés de son grand frère.Dans l'ensemble, les inconvénients d'un système statiquement typé mais déductible sont à peu près les mêmes que les inconvénients de la frappe statique en général, une discussion bien rodée sur ce site et bien d'autres de pages de guerres de flammes). Bien sûr, certains desdits inconvénients sont améliorés par la plus petite quantité d'annotations de type dans un système inférable. De plus, l'inférence de type a ses propres avantages: le développement par trous ne serait pas possible sans l'inférence de type.
Java * prouve qu'un langage nécessitant trop d'annotations de type devient ennuyeux, mais avec trop peu, vous perdez les avantages que j'ai décrits ci-dessus. Les langues avec inférence de type opt-out établissent un équilibre agréable entre les deux extrêmes.
* Même Java, ce grand bouc émissaire, effectue une certaine quantité d' inférence de type local . Dans une instruction comme
Map<String, Integer> = new HashMap<>();
, vous n'avez pas besoin de spécifier le type générique du constructeur. D'un autre côté, les langages de style ML sont généralement inférables à l' échelle mondiale.la source
Functor
. Les listes etmap
sont plus susceptibles d'être familières aux Haskellers non chevronnés.var
comme un exemple d'inférence de type?var
est un bon exemple.x
; dans ce dernier, il n'y a pas de type à déterminer, tous les types sont connus et il suffit de vérifier que l'expression a du sens. La différence devient plus importante lorsque vous passez devant des exemples triviaux etx
est utilisée à plusieurs endroits; le compilateur doit alors recouper les emplacements oùx
est utilisé pour déterminer 1) est-il possible d'affecterx
un type tel que le code saisira check? 2) Si c'est le cas, quel est le type le plus général que nous pouvons lui attribuer?new HashMap<>();
syntaxe n'a été ajoutée qu'en Java 7, et les lambdas en Java 8 permettent beaucoup d'inférence de type "réel".En C #, l'inférence de type se produit au moment de la compilation, donc le coût d'exécution est nul.
Pour des raisons de style,
var
est utilisé dans les situations où il n'est pas pratique ou inutile de spécifier manuellement le type. Linq est une de ces situations. Un autre est:sans lequel vous répéteriez votre nom de type très long (et les paramètres de type) plutôt que de simplement dire
var
.Utiliser le nom réel du type lorsqu'il est explicite améliore la clarté du code.
Il existe des situations où l'inférence de type ne peut pas être utilisée, comme les déclarations de variables de membre dont les valeurs sont définies au moment de la construction, ou où vous voulez vraiment qu'intellisense fonctionne correctement (l'EDI de Hackerrank n'intellectera pas les membres de la variable à moins que vous ne déclariez le type explicitement) .
la source
Bonne question!
Et il y a des langages plus ésotériques qui ne peuvent pas faire leur bizarrerie sans annotation de type explicite. Jusqu'à présent, il n'y en a aucun que je sache qui soit assez commun / populaire / prometteur pour le mentionner, sauf en passant.
la source
var foo = x => x;
échec parce que la langue doit inférerx
ici et n'a rien à continuer. Lorsque les lambdas sont construits, ils sont construits en tant que délégués explicitement typésFunc<int, int> foo = x => x
est intégré dans CIL commeFunc<int, int> foo = new Func<int, int>(x=>x);
où le lambda est construit en tant que fonction générée et explicitement typée. Pour moi, inférer le type dex
fait partie intégrante de l'inférence de type ...x => x
sont contenues dans le lambda lui-même - il ne fait référence à aucune variable de la portée environnante. Toute langue fonctionnelle serait sain d' esprit bien que son type infère est « pour tous les typesa
,a -> a
». Je pense que DeadMG essaie de dire que le système de type de C # n'a pas la propriété de type principal, ce qui signifie qu'il est toujours possible de trouver le type le plus général pour n'importe quelle expression. C'est une propriété très facile à détruire.Java se trouve être l'exception plutôt que la règle ici. Même C ++ (que je crois qualifier de "bon vieux langage" :)) prend en charge l'inférence de type avec le
auto
mot - clé depuis la norme C ++ 11. Il fonctionne non seulement avec la déclaration de variable, mais aussi comme type de retour de fonction, ce qui est particulièrement pratique avec certaines fonctions de modèle complexes.Le typage implicite et l'inférence de type ont de nombreux bons cas d'utilisation, et il y a aussi certains cas d'utilisation où vous ne devriez vraiment pas le faire. C'est parfois une question de goût et un sujet de débat.
Mais qu'il existe sans aucun doute de bons cas d'utilisation, est en soi une raison légitime pour tout langage de le mettre en œuvre. Ce n'est pas non plus une fonctionnalité difficile à implémenter, aucune pénalité d'exécution et n'affecte pas le temps de compilation de manière significative.
Je ne vois pas de réel inconvénient à donner au développeur la possibilité d'utiliser l'inférence de type.
Certains répondeurs se demandent à quel point la frappe explicite est bonne parfois, et ils ont certainement raison. Mais ne pas prendre en charge le typage implicite signifierait qu'un langage applique un typage explicite tout le temps.
Ainsi, le véritable inconvénient est lorsqu'un langage ne prend pas en charge le typage implicite, car avec cela, il indique qu'il n'y a aucune raison légitime pour le développeur de l'utiliser, ce qui n'est pas vrai.
la source
La principale distinction entre un système d'inférence de type Hindley-Milner et l'inférence de type Go est la direction du flux d'informations. Dans HM, saisissez les flux d'informations vers l'avant et vers l'arrière via l'unification; dans Go, saisissez uniquement les flux d'informations vers l'avant: il calcule uniquement les substitutions vers l'avant.
L'inférence de type HM est une splendide innovation qui fonctionne bien avec les langages fonctionnels de type polymorphe, mais les auteurs de Go diraient probablement qu'elle essaie d'en faire trop:
Le fait que l'information circule à la fois vers l'avant et vers l'arrière signifie que l'inférence de type HM est une affaire très non locale; en l'absence d'annotations de type, chaque ligne de code de votre programme pourrait contribuer à la saisie d'une seule ligne de code. Si vous ne disposez que d'une substitution directe, vous savez que la source d'une erreur de type doit être dans le code qui précède votre erreur; pas le code qui vient après.
Avec l'inférence de type HM, vous avez tendance à penser aux contraintes: lorsque vous utilisez un type, vous limitez les types possibles qu'il peut avoir. À la fin de la journée, il peut y avoir certaines variables de type qui sont laissées totalement sans contrainte. La perspicacité de l'inférence de type HM est que, ces types n'ont vraiment pas d'importance, et donc ils sont transformés en variables polymorphes. Cependant, ce polymorphisme supplémentaire peut être indésirable pour un certain nombre de raisons. Tout d'abord, comme certaines personnes l'ont souligné, ce polymorphisme supplémentaire pourrait être indésirable: HM concluant un faux, de type polymorphe pour certains faux codes, et conduisant à d'étranges erreurs plus tard. Deuxièmement, lorsqu'un type est laissé polymorphe, cela peut avoir des conséquences sur le comportement d'exécution. Par exemple, un résultat intermédiaire trop polymorphe est la raison pour laquelle «montrer. lire 'est considéré comme ambigu à Haskell; comme autre exemple,
la source
Cela nuit à la lisibilité.
Comparer
contre
C'est particulièrement un problème lors de la lecture en dehors d'un IDE comme sur github.
la source
var
pouvez l'utiliser sans nuire à la lisibilité.var objects = GetBusinessObjects();