Je pense que je comprends la frappe forte , mais chaque fois que je cherche des exemples de ce qu'est un typage faible, je finis par trouver des exemples de langages de programmation qui contraignent / convertissent simplement les types automatiquement.
Par exemple, dans cet article intitulé Typing: Strong vs Weak, Static vs Dynamic dit que Python est fortement typé car vous obtenez une exception si vous essayez de:
Python
1 + "1"
Traceback (most recent call last):
File "", line 1, in ?
TypeError: unsupported operand type(s) for +: 'int' and 'str'
Cependant, une telle chose est possible en Java et en C #, et nous ne les considérons pas faiblement typés juste pour cela.
Java
int a = 10;
String b = "b";
String result = a + b;
System.out.println(result);
C #
int a = 10;
string b = "b";
string c = a + b;
Console.WriteLine(c);
Dans cet autre article intitulé Weakly Type Languages, l'auteur dit que Perl est faiblement typé simplement parce que je peux concaténer une chaîne en un nombre et vice versa sans aucune conversion explicite.
Perl
$a=10;
$b="a";
$c=$a.$b;
print $c; #10a
Ainsi, le même exemple rend Perl faiblement typé, mais pas Java et C # ?.
Gee, c'est déroutant
Les auteurs semblent laisser entendre qu'un langage qui empêche l'application de certaines opérations sur des valeurs de types différents est fortement typé et au contraire signifie faiblement typé.
Par conséquent, à un moment donné, je me suis senti poussé à croire que si une langue fournit beaucoup de conversions automatiques ou de coercition entre les types (comme perl) peut finir par être considérée comme faiblement typée, alors que d'autres langues qui fournissent seulement quelques conversions peuvent finir par être considéré comme fortement typé.
J'ai tendance à croire, cependant, que je dois me tromper dans cette interprétation, je ne sais simplement pas pourquoi ni comment l'expliquer.
Donc, mes questions sont:
- Qu'est-ce que cela signifie vraiment pour une langue d'être vraiment faiblement typée?
- Pouvez-vous citer de bons exemples de frappe faible qui ne sont pas liés à la conversion automatique / à la coercition automatique effectuée par la langue?
- Une langue peut-elle être faiblement typée et fortement typée en même temps?
Réponses:
MISE À JOUR: Cette question a fait l'objet de mon blog le 15 octobre 2012. Merci pour la super question!
Cela signifie "ce langage utilise un système de type que je trouve déplaisant". Un langage "fortement typé" par contre est un langage avec un système de typage que je trouve agréable.
Les termes n'ont essentiellement aucun sens et vous devez les éviter. Wikipédia énumère onze significations différentes pour «fortement typé», dont plusieurs sont contradictoires. Cela indique que les risques de confusion créés sont élevés dans toute conversation impliquant le terme «fortement typé» ou «faiblement typé».
Tout ce que vous pouvez vraiment dire avec certitude, c'est qu'un langage "fortement typé" en discussion a une restriction supplémentaire dans le système de types, soit à l'exécution ou à la compilation, qu'un langage "faiblement typé" en discussion manque. Ce que cette restriction pourrait être ne peut être déterminé sans autre contexte.
Au lieu d'utiliser «fortement typé» et «faiblement typé», vous devez décrire en détail le type de sécurité de type que vous entendez. Par exemple, C # est un langage à typage statique et un langage de type sécurisé et un langage sans mémoire , pour la plupart. C # permet à ces trois formes de typage "fort" d'être violées. L'opérateur de cast enfreint le typage statique; il dit au compilateur "J'en sais plus que vous sur le type d'exécution de cette expression". Si le développeur se trompe, le runtime lèvera une exception afin de protéger la sécurité du type. Si le développeur souhaite interrompre la sécurité de type ou la sécurité de la mémoire, il peut le faire en désactivant le système de sécurité de type en créant un bloc "dangereux". Dans un bloc non sécurisé, vous pouvez utiliser la magie du pointeur pour traiter un int comme un flottant (violant la sécurité de type) ou pour écrire dans la mémoire que vous ne possédez pas. (Violation de la sécurité de la mémoire.)
C # impose des restrictions de type qui sont vérifiées à la fois à la compilation et à l'exécution, ce qui en fait un langage «fortement typé» par rapport aux langages qui font moins de vérification à la compilation ou moins de vérification à l'exécution. C # vous permet également, dans des circonstances spéciales, d'effectuer une exécution finale autour de ces restrictions, ce qui en fait un langage «faiblement typé» par rapport aux langages qui ne vous permettent pas d'effectuer une telle exécution finale.
Qu'est-ce que c'est vraiment? Il est impossible de dire; cela dépend du point de vue du locuteur et de son attitude vis-à-vis des différentes caractéristiques du langage.
la source
Comme d'autres l'ont noté, les termes «fortement typé» et «faiblement typé» ont tellement de significations différentes qu'il n'y a pas de réponse unique à votre question. Cependant, puisque vous avez spécifiquement mentionné Perl dans votre question, laissez-moi essayer d'expliquer dans quel sens Perl est faiblement typé.
Le fait est que, en Perl, il n'existe pas de "variable entière", de "variable flottante", de "variable chaîne" ou de "variable booléenne". En fait, dans la mesure où l'utilisateur peut ( en général) dire, il n'y a même pas entier, virgule flottante, chaîne ou booléen valeurs : tout ce que vous avez sont « scalaires », qui sont toutes ces choses en même temps. Ainsi, vous pouvez, par exemple, écrire:
Bien sûr, comme vous le notez correctement, tout cela peut être considéré comme une simple coercition de type. Mais le fait est qu'en Perl, les types sont toujours forcés. En fait, il est assez difficile pour un utilisateur de dire quel pourrait être le "type" interne d'une variable: à la ligne 2 de mon exemple ci-dessus, demander si la valeur de
$bar
est la chaîne"9"
ou le nombre9
n'a pratiquement pas de sens, car, comme en ce qui concerne Perl, c'est la même chose . En effet, il est même possible pour un scalaire Perl d'avoir en interne à la fois une chaîne et une valeur numérique en même temps, comme c'est par exemple le cas$foo
après la ligne 2 ci-dessus.Le revers de tout cela est que, puisque les variables Perl ne sont pas typées (ou plutôt n'exposent pas leur type interne à l'utilisateur), les opérateurs ne peuvent pas être surchargés pour faire des choses différentes pour différents types d'arguments; vous ne pouvez pas simplement dire "cet opérateur fera X pour les nombres et Y pour les chaînes", car l'opérateur ne peut pas (ne veut pas) dire quel type de valeurs sont ses arguments.
Ainsi, par exemple, Perl a et a besoin à la fois d'un opérateur d'addition numérique (
+
) et d'un opérateur de concaténation de chaînes (.
): comme vous l'avez vu ci-dessus, il est parfaitement bien d'ajouter des chaînes ("1" + "2" == "3"
) ou de concaténer des nombres (1 . 2 == 12
). De même, les opérateurs de comparaison numériques==
,!=
,<
,>
,<=
,>=
et<=>
comparer les valeurs numériques de leurs arguments, alors que les opérateurs de comparaison de chaîneseq
,ne
,lt
,gt
,le
,ge
etcmp
les comparer lexicographique sous forme de chaînes. Donc2 < 10
, mais2 gt 10
(mais"02" lt 10
, pendant"02" == 2
). (Attention, certains autres langages, comme JavaScript, essaient de prendre en charge un typage faible de type Perl tout enfaisant également la surcharge de l'opérateur. Cela conduit souvent à la laideur, comme la perte d'associativité pour+
.)(Le problème ici est que, pour des raisons historiques, Perl 5 a quelques cas d'angle, comme les opérateurs logiques au niveau du bit, dont le comportement dépend de la représentation interne de leurs arguments. Ceux-ci sont généralement considérés comme un défaut de conception ennuyeux, car la représentation interne peut changer pour des raisons surprenantes, et donc prédire ce que ces opérateurs font dans une situation donnée peut être délicat.)
Cela dit, on pourrait dire que Perl n'avoir des types forts; ce ne sont tout simplement pas les types auxquels vous pourriez vous attendre. Plus précisément, en plus du type "scalaire" décrit ci-dessus, Perl a également deux types structurés: "array" et "hash". Ceux-ci sont très distincts des scalaires, au point où les variables Perl ont des sigils différents indiquant leur type ( pour les scalaires, pour les tableaux, pour les hachages) 1 . Il existe des règles de coercition entre ces types, vous pouvez donc écrire par exemple , mais beaucoup d'entre elles sont assez avec perte: par exemple, assigne la longueur du tableau à
$
@
%
%foo = @bar
$foo = @bar
@bar
$foo
, pas son contenu. (En outre, il existe quelques autres types étranges, comme les typesglobs et les poignées d'E / S, que vous ne voyez pas souvent exposés.)De plus, une légère lacune dans cette belle conception est l'existence de types de référence, qui sont un type spécial de scalaires (et qui peuvent être distingués des scalaires normaux, en utilisant l'
ref
opérateur). Il est possible d'utiliser des références comme des scalaires normaux, mais leurs valeurs chaîne / numérique ne sont pas particulièrement utiles, et elles ont tendance à perdre leur référence spéciale si vous les modifiez en utilisant des opérations scalaires normales. De plus, toute variable Perl 2 peut être un paradigme. L'opinion générale est que si vous vous trouvez en train de vérifier la classe d'un objet en Perl, vous faites quelque chose de mal.bless
éditée dans une classe, la transformant en un objet de cette classe; le système de classes OO en Perl est quelque peu orthogonal au système de type primitif (ou sans type) décrit ci-dessus, bien qu'il soit également «faible» dans le sens de suivre le typage canard1 En fait, le sigil désigne le type de la valeur à laquelle on accède, de sorte que par exemple le premier scalaire du tableau
@foo
est désigné$foo[0]
. Voir perlfaq4 pour plus de détails.2 Les objets en Perl sont (normalement) accédés par des références à eux, mais ce qui est réellement modifié
bless
est la variable (probablement anonyme) vers laquelle pointe la référence. Cependant, la bénédiction est en effet une propriété de la variable, pas de sa valeur, donc par exemple, attribuer la variable bénie réelle à une autre vous en donne juste une copie superficielle et non bénie. Voir perlobj pour plus de détails.la source
En plus de ce qu'Eric a dit, considérez le code C suivant:
Contrairement aux langages tels que Python, C #, Java ou autres, ce qui précède est faiblement typé car nous perdons des informations de type. Eric a correctement fait remarquer qu'en C #, nous pouvons contourner le compilateur en effectuant un casting, en lui disant effectivement «J'en sais plus sur le type de cette variable que vous».
Mais même dans ce cas, le runtime vérifiera toujours le type! Si le cast n'est pas valide, le système d'exécution l'attrapera et lèvera une exception.
Avec l'effacement de type, cela ne se produit pas - les informations de type sont jetées. Un casting
void*
en C fait exactement cela. À cet égard, ce qui précède est fondamentalement différent d'une déclaration de méthode C # telle quevoid f(Object x)
.(Techniquement, C # permet également l'effacement de type via un code non sécurisé ou un marshalling.)
C'est aussi faiblement tapé que possible. Tout le reste est juste une question de vérification de type statique ou dynamique, c'est-à-dire du moment où un type est vérifié.
la source
void*
franchit les deux contrôles de type. L'effacement de type générique ne le fait pas, il contourne seulement les contrôles à la compilation. C'est exactement comme les moulages explicites (mentionnés par Eric) à cet égard.Un exemple parfait vient de l'article wikipedia de Strong Typing :
Un typage généralement fort implique que le langage de programmation impose des restrictions sévères sur le mélange qui est autorisé à se produire.
Faible frappe
Typage fort
Notez qu'un langage de frappe faible peut mélanger différents types sans erreurs. Un langage de type fort nécessite que les types d'entrée soient les types attendus. Dans un langage de type fort, un type peut être converti (
str(a)
convertit un entier en chaîne) ou cast (int(b)
).Tout dépend de l'interprétation de la frappe.
la source
Je voudrais contribuer à la discussion avec mes propres recherches sur le sujet, comme d'autres commentent et contribuent, j'ai lu leurs réponses et suivi leurs références et j'ai trouvé des informations intéressantes. Comme suggéré, il est probable que la plupart de ces questions seraient mieux discutées dans le forum des programmeurs, car cela semble être plus théorique que pratique.
D'un point de vue théorique, je pense que l'article de Luca Cardelli et Peter Wegner intitulé On Understanding Types, Data Abstraction and Polymorphism a l'un des meilleurs arguments que j'ai lus.
Cette déclaration semble suggérer qu'un typage faible nous permettrait d'accéder à la structure interne d'un type et de la manipuler comme s'il s'agissait de quelque chose d'autre (un autre type). Peut-être ce que nous pourrions faire avec du code non sécurisé (mentionné par Eric) ou avec des pointeurs effacés de type c mentionnés par Konrad.
L'article continue ...
En tant que tel, un typage fort signifie l'absence d'erreurs de type, je ne peux que supposer qu'un typage faible signifie le contraire: la présence probable d'erreurs de type. Au moment de l'exécution ou de la compilation? Cela ne semble pas pertinent ici.
Chose amusante, selon cette définition, un langage avec des coercitions de type puissantes comme Perl serait considéré comme fortement typé, car le système n'échoue pas, mais il traite les types en les contraignant à des équivalences appropriées et bien définies.
D'autre part, pourrais-je dire que l'allocation de
ClassCastException
etArrayStoreException
(en Java) etInvalidCastException
,ArrayTypeMismatchException
(en C #) indiquerait un niveau de typage faible, au moins au moment de la compilation? La réponse d'Eric semble être d'accord avec cela.Dans un deuxième article intitulé Typeful Programming fourni dans l'une des références fournies dans l'une des réponses à cette question, Luca Cardelli se penche sur le concept de violations de type:
En tant que telles, les coercitions de type comme celles fournies par les opérateurs pourraient être considérées comme des violations de type, mais à moins qu'elles ne rompent la cohérence du système de types, nous pourrions dire qu'elles ne conduisent pas à un système faiblement typé.
Sur cette base, ni Python, Perl, Java ou C # ne sont faiblement typés.
Cardelli mentionne deux vilations de type que je considère très bien comme des cas de typage vraiment faible:
Ce genre de choses possible dans des langages comme C (mentionné par Konrad) ou via du code unsafe dans .Net (mentionné par Eric) impliquerait vraiment de taper faiblement.
Je crois que la meilleure réponse à ce jour est celle d'Eric, car la définition de ces concepts est très théorique, et lorsqu'il s'agit d'un langage particulier, les interprétations de tous ces concepts peuvent conduire à des conclusions discutables différentes.
la source
Un typage faible signifie en effet qu'un pourcentage élevé de types peut être implicitement contraint, en essayant de deviner ce que le codeur voulait.
Un typage fort signifie que les types ne sont pas forcés, ou du moins moins forcés.
Le typage statique signifie que les types de vos variables sont déterminés au moment de la compilation.
De nombreuses personnes ont récemment confondu «manifestement typé» avec «fortement typé». «Manifestement typé» signifie que vous déclarez explicitement les types de vos variables.
Python est principalement fortement typé, bien que vous puissiez utiliser presque tout dans un contexte booléen, et les booléens peuvent être utilisés dans un contexte entier, et vous pouvez utiliser un entier dans un contexte flottant. Il n'est pas manifestement typé, car vous n'avez pas besoin de déclarer vos types (sauf pour Cython, qui n'est pas entièrement python, bien qu'intéressant). Il n'est pas non plus typé statiquement.
C et C ++ sont manifestement typés, statiquement typés et quelque peu fortement typés, car vous déclarez vos types, les types sont déterminés au moment de la compilation, et vous pouvez mélanger des entiers et des pointeurs, ou des entiers et des doubles, ou même convertir un pointeur vers un type en un pointeur vers un autre type.
Haskell est un exemple intéressant, car il n'est pas manifestement typé, mais il est aussi statiquement et fortement typé.
la source
Le typage fort <=> faible ne concerne pas seulement le continuum sur la quantité ou le peu de valeurs qui sont automatiquement forcées par la langue pour un type de données à un autre, mais la force ou la faiblesse des valeurs réelles typées. En Python et Java, et principalement en C #, les valeurs ont leurs types gravés dans la pierre. En Perl, pas tellement - il n'y a vraiment qu'une poignée de types de valeurs différents à stocker dans une variable.
Ouvrons les cas un par un.
Python
Dans l'exemple Python
1 + "1"
, l'+
opérateur appelle le__add__
type forint
en lui donnant la chaîne"1"
comme argument - cependant, cela se traduit par NotImplemented:Ensuite, l'interpréteur essaie le
__radd__
of str:Lorsqu'il échoue, l'
+
opérateur échoue avec le résultatTypeError: unsupported operand type(s) for +: 'int' and 'str'
. En tant que telle, l'exception ne dit pas grand-chose sur le typage fort, mais le fait que l'opérateur+
ne contraint pas automatiquement ses arguments au même type, est un indicateur sur le fait que Python n'est pas le langage le plus faiblement typé du continuum.D'autre part, en Python
'a' * 5
est implémenté:C'est,
Le fait que l'opération soit différente nécessite un typage fort - cependant le contraire de
*
forcer les valeurs à des nombres avant de multiplier encore ne rendrait pas nécessairement les valeurs faiblement typées.Java
L'exemple Java
String result = "1" + 1;
ne fonctionne que parce que par commodité, l'opérateur+
est surchargé pour les chaînes. L'+
opérateur Java remplace la séquence par la création d'unStringBuilder
(voir ceci ):Ceci est plutôt un exemple de typage très statique, sans aucune contrainte réelle -
StringBuilder
a une méthodeappend(Object)
qui est spécifiquement utilisée ici. La documentation dit ce qui suit:Où
String.valueOf
alorsIl s'agit donc d'un cas d'absolument aucune contrainte de la part du langage - déléguant toute préoccupation aux objets eux-mêmes.
C #
Selon la réponse de Jon Skeet ici , l'opérateur
+
n'est même pas surchargé pour lastring
classe - à l'instar de Java, ce n'est que la commodité générée par le compilateur, grâce à la fois à un typage statique et fort.Perl
Comme l' explique la perldata ,
Cependant, Perl n'a pas de type de données séparé pour les nombres, les booléens, les chaînes, les valeurs nulles, les
undefined
s, les références à d'autres objets, etc. - il n'a qu'un seul type pour tous, le type scalaire; 0 est une valeur scalaire autant que "0". Une variable scalaire qui a été définie comme une chaîne peut vraiment se transformer en nombre, et à partir de là, se comporter différemment de "juste une chaîne", si elle est accédée dans un contexte numérique. Le scalaire peut contenir n'importe quoi en Perl, c'est autant l'objet qu'il existe dans le système. alors qu'en Python les noms font simplement référence aux objets, en Perl les valeurs scalaires dans les noms sont des objets modifiables. De plus, le système de type orienté objet est collé dessus: il n'y a que 3 types de données dans perl - scalaires, listes et hachages. Un objet défini par l'utilisateur en Perl est une référence (c'est-à-dire un pointeur vers l'une des 3 précédentes)bless
éditée vers un paquet - vous pouvez prendre une telle valeur et la donner à n'importe quelle classe à tout moment.Perl vous permet même de changer les classes de valeurs à volonté - ce n'est pas possible en Python où pour créer une valeur d'une classe, vous devez explicitement construire la valeur appartenant à cette classe avec
object.__new__
ou similaire. En Python, vous ne pouvez pas vraiment changer l'essence de l'objet après la création, en Perl vous pouvez faire beaucoup de choses:ainsi l'identité de type est faiblement liée à la variable, et elle peut être modifiée par n'importe quelle référence à la volée. En fait, si vous faites
\$another
n'a pas l'identité de classe, même s'il\$val
donnera toujours la référence bénie.TL; DR
Il y a beaucoup plus à propos du typage faible en Perl que de simples coercitions automatiques, et il s'agit davantage du fait que les types de valeurs eux-mêmes ne sont pas gravés dans la pierre, contrairement au Python qui est un langage dynamiquement mais très fortement typé. Ce python donne
TypeError
sur1 + "1"
est une indication que la langue est fortement typé, même si celui contraire de faire quelque chose d' utile, comme en Java ou C # ne les empêche pas d' être un langage fortement typé.la source
Comme beaucoup d'autres l'ont exprimé, toute la notion de typage "fort" vs "faible" pose problème.
En tant qu'archétype, Smalltalk est très fortement typé - il lèvera toujours une exception si une opération entre deux objets est incompatible. Cependant, je soupçonne que peu de personnes sur cette liste appelleraient Smalltalk un langage fortement typé, car il est typé dynamiquement.
Je trouve la notion de typage «statique» versus «dynamique» plus utile que «fort» par rapport à «faible». Un langage à typage statique a tous les types déterminés au moment de la compilation, et le programmeur doit déclarer explicitement le cas échéant.
Contraste avec un langage à typage dynamique, où la saisie est effectuée au moment de l'exécution. C'est généralement une exigence pour les langages polymorphes, de sorte que les décisions sur la légalité d'une opération entre deux objets ne doivent pas être décidées à l'avance par le programmeur.
Dans les langages polymorphes, typés dynamiquement (comme Smalltalk et Ruby), il est plus utile de penser à un «type» comme une «conformité au protocole». Si un objet obéit à un protocole de la même manière qu'un autre objet - même si les deux objets ne partagent aucun héritage ou mixins ou autre vaudou - ils sont considérés comme du même «type» par le système d'exécution. Plus correctement, un objet dans de tels systèmes est autonome et peut décider s'il est logique de répondre à un message particulier se référant à un argument particulier.
Vous voulez un objet qui peut apporter une réponse significative au message "+" avec un argument d'objet qui décrit la couleur bleue? Vous pouvez le faire dans des langues à typage dynamique, mais c'est une douleur dans les langues à typage statique.
la source
J'aime la réponse de @Eric Lippert , mais pour répondre à la question - les langages fortement typés ont généralement une connaissance explicite des types de variables à chaque point du programme. Les langages faiblement typés ne le font pas, ils peuvent donc tenter d'effectuer une opération qui peut ne pas être possible pour un type particulier. Il pense que le moyen le plus simple de voir cela est dans une fonction. C ++:
La variable
a
est connue pour être de type chaîne et toute opération incompatible sera interceptée au moment de la compilation.Python:
La variable
a
peut être n'importe quoi et nous pouvons avoir du code qui appelle une méthode non valide, qui ne sera interceptée qu'au moment de l'exécution.la source