web-dev-qa-db-fra.com

Demander des éclaircissements sur les contradictions apparentes concernant les langues faiblement typées

Je pense que je comprends typage fort , mais chaque fois que je cherche des exemples pour ce qui 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 nommé 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 nommé 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 enter image description here

Les auteurs semblent impliquer qu'un langage qui empêche l'application de certaines opérations sur des valeurs de différents types est fortement typé et au contraire signifie faiblement typé.

Par conséquent, à un moment donné, je me suis senti incité à croire que si une langue fournit un grand nombre de conversions automatiques ou de coercition entre types (comme Perl) peut finir par être considéré comme faiblement typé, tandis que d'autres langues qui ne fournissent que quelques conversions peuvent finir par être considéré comme fortement typé.

Je suis enclin à croire, cependant, que je dois me tromper dans cette interprétation, je ne sais tout simplement pas pourquoi ni comment l'expliquer.

Donc, mes questions sont:

  • Qu'est-ce que cela signifie vraiment qu'une langue soit vraiment faiblement typée?
  • Pourriez-vous citer de bons exemples de frappe faible qui ne sont pas liés à la conversion automatique/coercition automatique effectuée par la langue?
  • Une langue peut-elle être faiblement typée et fortement typée en même temps?
176
Edwin Dalorzo

MISE À JOUR: Cette question a fait l'objet de mon blog le 15 octobre 2012. Merci pour la grande question!


Qu'est-ce que cela signifie vraiment qu'une langue soit "faiblement typée"?

Cela signifie "cette langue utilise un système de type que je trouve désagréable". Par contre, une langue "fortement typée" est une langue avec un système de caractères que je trouve agréable.

Les termes sont essentiellement dénués de sens et vous devez les éviter. Wikipedia répertorie onze significations différentes pour "fortement typées", dont plusieurs sont contradictoires. Cela indique que les risques de confusion créés sont élevés dans toute conversation impliquant le terme "fortement tapé" ou "faiblement tapé".

Tout ce que vous pouvez vraiment dire avec certitude, c'est qu'un langage "fortement typé" en cours de discussion a une restriction supplémentaire dans le système de type, soit au moment de l'exécution soit au moment de la compilation, qu'il manque un langage "faiblement typé" en cours de discussion. 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 de type statique et un langage de type sûr et un langage sûr , pour la plupart . C # permet de violer ces trois formes de frappe "forte". L'opérateur de transtypage viole 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é des types. Si le développeur souhaite briser 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 dangereux, 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. (Violer la sécurité de la mémoire.)

C # impose des restrictions de type qui sont vérifiées au moment de la compilation et au moment de l'exécution, ce qui en fait un langage "fortement typé" par rapport aux langages qui effectuent moins de vérification au moment de la compilation ou moins de vérification au moment de l'exécution. C # vous permet également, dans des circonstances spéciales, de faire un tour de passe-passe autour de ces restrictions, ce qui en fait un langage "faiblement typé" par rapport aux langues qui ne vous permettent pas de faire un tel tour de fin.

C'est quoi 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 linguistiques.

209
Eric Lippert

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, permettez-moi d'essayer d'expliquer dans quel sens Perl est faiblement typé.

Le fait est qu'en Perl, il n'existe pas de "variable entière", de "variable flottante", de "variable de chaîne" ou de "variable booléenne". En fait, pour autant que l'utilisateur puisse (généralement) le dire, il n'y a même pas de valeurs entières, flottantes, chaîne ou booléennes : tout ce que vous avez sont "scalaires", qui sont toutes ces choses en même temps. Vous pouvez donc, par exemple, écrire:

$foo = "123" + "456";           # $foo = 579
$bar = substr($foo, 2, 1);      # $bar = 9
$bar .= " lives";               # $bar = "9 lives"
$foo -= $bar;                   # $foo = 579 - 9 = 570

Bien sûr, comme vous le constatez correctement, tout cela peut être considéré comme une simple contrainte de type. Mais le fait est que, en Perl, les types sont toujours contraints. 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, demandant si la valeur de $bar est la chaîne "9" ou le nombre 9 est à peu près vide de sens, car, en ce qui concerne Perl, ce sont 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 le cas par exemple le cas pour $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 différentes choses 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 un opérateur de concaténation de chaînes (.): comme vous l'avez vu ci-dessus, il est parfaitement possible d'ajouter des chaînes ("1" + "2" == "3") ou pour concaténer des nombres (1 . 2 == 12). De même, les opérateurs de comparaison numériques ==, !=, <, >, <=, >= et <=> compare les valeurs numériques de leurs arguments, tandis que les opérateurs de comparaison de chaînes eq, ne, lt, gt, le, ge et cmp les comparent lexicographiquement comme des chaînes. Alors 2 < 10, mais 2 gt 10 (mais "02" lt 10, tandis que "02" == 2). (Attention, certaines autres langues , comme JavaScript, tentent de s'adapter à la frappe faible de type Perl tandis que également faire une surcharge d'opérateur. Cela conduit souvent à la laideur, comme la perte d'associativité pour +.)

(La mouche dans la pommade ici est que, pour des raisons historiques, Perl 5 a quelques cas de coin, 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 il peut donc être difficile de prédire exactement ce que font ces opérateurs dans une situation donnée.)

Cela dit, on pourrait soutenir que Perl possède des types forts; ce ne sont tout simplement pas le genre de types auxquels on pourrait s'attendre. Plus précisément, en plus du type "scalaire" discuté ci-dessus, Perl a également deux types structurés: "tableau" et "hachage". Ce sont très distincts des scalaires, au point où les variables Perl ont différentes sigils indiquant leur type ($ pour les scalaires, @ pour les tableaux, % pour les hachages)1. Il y a des règles de coercition entre ces types, donc vous pouvez écrire par ex. %foo = @bar, mais beaucoup d'entre eux sont assez déficients: par exemple, $foo = @bar affecte la longueur du tableau @bar à $foo, pas son contenu. (En outre, il existe quelques autres types étranges, tels que les globes de type et les poignées d'E/S, que vous ne voyez pas souvent exposés.)

En outre, une légère faille dans cette conception de Nice 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 , à l'aide de l'opérateur ref). Il est possible d'utiliser des références en tant que 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 à l'aide d'opérations scalaires normales. En outre, toute variable Perl2 peut être blessed à une classe, le transformant en un objet de cette classe; le système de classe 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 de canard = paradigme. L'opinion générale est que, si vous vous retrouvez à vérifier la classe d'un objet en Perl, vous faites quelque chose de mal.


1 En fait, le sceau indique le type de la valeur accédée, de sorte que par ex. le premier scalaire du tableau @foo est noté $foo[0]. Voir perlfaq4 pour plus de détails.

2 Les objets en Perl sont (normalement) accessibles via des références à eux, mais ce qui est réellement blessed est la variable (éventuellement anonyme) vers laquelle la référence pointe. Cependant, la bénédiction est en effet une propriété de la variable, pas de sa valeur, donc par ex. qu'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.

64
Ilmari Karonen

En plus de ce que Eric a dit, considérez le code C suivant:

void f(void* x);

f(42);
f("hello");

Contrairement à des langages tels que Python, C #, Java ou autre), ce qui précède est faiblement typé parce que nous perdons saisissons les informations. Eric a correctement souligné qu'en C # nous pouvons contourner le compilateur en transtypant, en lui disant effectivement "Je connais mieux le type de cette variable que vous".

Mais même alors, le runtime vérifiera toujours le type! Si le cast n'est pas valide, le système d'exécution le rattrapera et lèvera une exception.

Avec l'effacement de type, cela ne se produit pas - les informations de type sont jetées. Un transtypage vers 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 que void f(Object x).

(Techniquement, C # permet également l'effacement de type via un code non sécurisé ou un marshalling.)

This est aussi faiblement typé que possible. Tout le reste n'est qu'une question de vérification de type statique ou dynamique, c'est-à-dire du moment quand un type est vérifié.

19
Konrad Rudolph

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 peut se produire.

Typage faible

a = 2
b = "2"

concatenate(a, b) # returns "22"
add(a, b) # returns 4

Typage fort

a = 2
b = "2"

concatenate(a, b) # Type Error
add(a, b) # Type Error
concatenate(str(a), b) #Returns "22"
add(a, int(b)) # Returns 4

Notez qu'un langage de frappe faible peut mélanger différents types sans erreur. Un langage de type fort requiert 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 converti (int(b)).

Tout dépend de l'interprétation de la frappe.

14
SaulBack

Un typage faible signifie en effet qu'un pourcentage élevé de types peut être implicitement contraint, 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.

Beaucoup de gens ont récemment confondu "manifestement typé" avec "fortement typé". "Manifestement typé" signifie que vous déclarez explicitement les types de vos variables.

Python est généralement fortement typé, bien que vous puissiez utiliser presque n'importe quoi 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 en 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 transtyper 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 également statiquement et fortement typé.

4
user1277476

Je voudrais contribuer à la discussion avec mes propres recherches sur le sujet, tandis que 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 elles semblent être plus théoriques que pratiques.

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.

Un type peut être considéré comme un ensemble de vêtements (ou une armure) qui protège une représentation sous-jacente non typée contre toute utilisation arbitraire ou involontaire. Il fournit un revêtement protecteur qui cache la représentation sous-jacente et limite la façon dont les objets peuvent interagir avec d'autres objets. Dans un système non typé, les objets non typés sont nus en ce que la représentation sous-jacente est exposée pour que tous puissent la voir. Violer le système de caractères implique de retirer l'ensemble de vêtements de protection et d'opérer directement sur la représentation nue.

Cette affirmation semble suggérer qu'un faible typage nous permettrait d'accéder à la structure interne d'un type et de le manipuler comme s'il s'agissait d'autre chose (un autre type). Peut-être ce que nous pourrions faire avec du code dangereux (mentionné par Eric) ou avec des pointeurs effacés de type c mentionnés par Konrad.

L'article continue ...

Les langues dans lesquelles toutes les expressions sont cohérentes en termes de type sont appelées langues fortement typées. Si un langage est fortement typé, son compilateur peut garantir que les programmes qu'il accepte s'exécuteront sans erreur de type. En général, nous devons nous efforcer de taper fort et adopter le typage statique chaque fois que possible. Notez que chaque langue typée statiquement est fortement typée mais l'inverse n'est pas nécessairement vrai.

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? Semble hors de propos ici.

Chose drôle, selon cette définition, un langage avec des coercitions de type puissantes comme Perl serait considéré comme fortement typé, parce que le système n'échoue pas, mais il traite les types en les contraignant en équivalences appropriées et bien définies.

D’un autre côté, pourrais-je dire que l’allocation de ClassCastException et ArrayStoreException (en Java) et InvalidCastException, ArrayTypeMismatchException (en C #) indiquerait une niveau de frappe faible, au moins au moment de la compilation? La réponse d'Eric semble d'accord avec cela.

Dans un deuxième article nommé 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 violation de type:

La plupart des langages de programmation système autorisent des violations de type arbitraire, certaines sans discrimination, certaines uniquement dans des parties restreintes d'un programme. Les opérations impliquant des violations de type sont appelées non fiables. Les violations de type entrent dans plusieurs classes [parmi lesquelles nous pouvons mentionner]:

Contraintes de valeur de base : il s'agit notamment des conversions entre entiers, booléens, caractères, ensembles, etc. Il n'y a pas besoin de violations de type ici, car intégré des interfaces peuvent être prévues pour effectuer les coercitions de manière typographique.

En tant que telles, les coercitions de type telles que celles fournies par les opérateurs peuvent être considérées comme des violations de type, mais à moins qu'elles ne brisent la cohérence du système de type, nous pouvons dire qu'elles ne conduisent pas à un système faiblement typé.

Sur cette base, ni Python, Perl, Java ou C # sont faiblement typés.

Cardelli mentionne deux types de dénigrement que je considère très bien comme des cas de frappe vraiment faible:

Arithmétique des adresses. Si nécessaire, il devrait y avoir une interface intégrée (non saine), fournissant les opérations adéquates sur les adresses et les conversions de types. Diverses situations impliquent des pointeurs dans le tas (très dangereux avec le déplacement des collecteurs), des pointeurs vers la pile, des pointeurs vers des zones statiques et des pointeurs vers d'autres espaces d'adressage. Parfois, l'indexation des tableaux peut remplacer l'arithmétique des adresses. Mappage de la mémoire. Cela implique de regarder une zone de mémoire comme un tableau non structuré, bien qu'il contienne des données structurées. Ceci est typique des allocateurs de mémoire et des collecteurs.

Ce genre de choses possibles dans des langages comme C (mentionné par Konrad) ou par le biais de code dangereux dans .Net (mentionné par Eric) impliquerait vraiment une faible frappe.

Je crois que la meilleure réponse jusqu'à présent 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.

4
Edwin Dalorzo

Le fort <=> typage faible ne concerne pas seulement le continuum sur la quantité ou le peu de valeurs qui sont forcées automatiquement par la langue pour un type de données à un autre, mais sur la force ou la faiblesse du réel les valeurs sont saisies. Dans Python et Java, et surtout en C #, les valeurs ont leurs types définis dans la pierre. En Perl, pas tellement - il n'y a vraiment qu'une poignée de différents types de valeurs à stocker dans une variable.

Ouvrons les cas un par un.


Python

Dans Python exemple 1 + "1", +, l'opérateur appelle __add__ pour le type int en lui donnant la chaîne "1" comme argument - cependant, cela se traduit par Non implémenté:

>>> (1).__add__('1')
NotImplemented

Ensuite, l'interpréteur essaie le __radd__ de str:

>>> '1'.__radd__(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute '__radd__'

En cas d'échec, l'opérateur + échoue avec le résultat TypeError: unsupported operand type(s) for +: 'int' and 'str'. En tant que tel, l'exception ne dit pas grand-chose sur le typage fort, mais le fait que l'opérateur + ne contraint pas ses arguments automatiquement au même type, est un pointeur sur le fait que Python n'est pas le langage le moins typé du continuum.

En revanche, dans Python 'a' * 5 est implémenté:

>>> 'a' * 5
'aaaaa'

C'est,

>>> 'a'.__mul__(5)
'aaaaa'

Le fait que l'opération soit différente nécessite un typage fort - cependant l'opposé de * contraindre les valeurs aux nombres avant de les multiplier ne rendra pas nécessairement les valeurs faiblement typées.


Java

L'exemple Java, String result = "1" + 1; ne fonctionne que parce que pour des raisons de commodité, l'opérateur + est surchargé pour les chaînes. L'opérateur Java + remplace la séquence par la création d'une StringBuilder (voir this ):

String result = a + b;
// becomes something like
String result = new StringBuilder().append(a).append(b).toString()

Ceci est plutôt un exemple de typage très statique, sans aucune contrainte réelle - StringBuilder a une méthode append(Object) qui est spécifiquement utilisée ici. La documentation indique ce qui suit:

Ajoute la représentation sous forme de chaîne de l'argument Object.

L'effet global est exactement comme si l'argument était converti en chaîne par la méthode String.valueOf(Object), et les caractères de cette chaîne étaient ensuite ajoutés à cette séquence de caractères.

String.valueOf puis

Renvoie la représentation sous forme de chaîne de l'argument Object. [Renvoie] si l'argument est null, alors une chaîne égale à "null"; sinon, la valeur de obj.toString() est renvoyée.

Il s'agit donc d'un cas d'absence totale de coercition de la part du langage - déléguant toute préoccupation aux objets eux-mêmes.


C #

Selon la Jon Skeet answer here , l'opérateur + n'est même pas surchargé pour la classe string - semblable à Java, ceci est simplement généré par commodité par le compilateur, grâce à la fois au typage statique et fort.


Perl

Comme l'explique le perldata ,

Perl a trois types de données intégrés: scalaires, tableaux de scalaires et tableaux associatifs de scalaires, appelés "hachages". Un scalaire est une chaîne unique (de n'importe quelle taille, limitée uniquement par la mémoire disponible), un nombre ou une référence à quelque chose (qui sera discuté dans perlref). Les tableaux normaux sont des listes ordonnées de scalaires indexés par un numéro, commençant par 0. Les hachages sont des collections non ordonnées de valeurs scalaires indexées par leur clé de chaîne associée.

Perl n'a cependant pas de type de données distinct pour les nombres, les booléens, les chaînes, les valeurs nulles, undefineds, les références à d'autres objets, etc. - il n'a qu'un seul type pour tout cela, le type scalaire; 0 est une valeur scalaire autant que "0". Un scalaire variable qui a été défini comme une chaîne peut vraiment se transformer en un nombre, et à partir de là se comporter différemment de "juste une chaîne", si on y accède 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 que dans Python les noms se réfèrent simplement 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é en plus: il n'y a que 3 types de données en 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'un des 3 précédents) blessed à un package - vous pouvez prendre une telle valeur et la bénir dans n'importe quelle classe à tout moment que vous voulez.

Perl vous permet même de changer les classes de valeurs à volonté - ce n'est pas possible dans Python où créer une valeur d'une classe dont vous avez besoin pour construire explicitement la valeur appartenant à cette classe avec object.__new__ ou similaire. Dans Python vous ne pouvez pas vraiment changer l'essence de l'objet après la création, dans Perl vous pouvez faire beaucoup de choses:

package Foo;
package Bar;

my $val = 42;
# $val is now a scalar value set from double
bless \$val, Foo;
# all references to $val now belong to class Foo
my $obj = \$val;
# now $obj refers to the SV stored in $val
# thus this prints: Foo=SCALAR(0x1c7d8c8)
print \$val, "\n"; 
# all references to $val now belong to class Bar
bless \$val, Bar;
# thus this prints Bar=SCALAR(0x1c7d8c8)
print \$val, "\n";
# we change the value stored in $val from number to a string
$val = 'abc';
# yet still the SV is blessed: Bar=SCALAR(0x1c7d8c8)
print \$val, "\n";
# and on the course, the $obj now refers to a "Bar" even though
# at the time of copying it did refer to a "Foo".
print $obj, "\n";

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 le faites

my $another = $val;

\$another n'a pas l'identité de classe, même si \$val donnera toujours la référence bénie.


TL; DR

Il y a beaucoup plus à propos du typage faible vers Perl que des coercitions automatiques, et il s'agit davantage du fait que les types des valeurs elles-mêmes ne sont pas définis dans la pierre, contrairement au Python qui est un langage dynamiquement mais très fortement typé. Que python donne TypeError sur 1 + "1" est une indication que la langue est fortement typée, même si l'inverse consiste à faire quelque chose d'utile, comme dans Java ou C # ne les empêche pas d'être des langages fortement typés.

3
Antti Haapala

Comme beaucoup d'autres l'ont exprimé, toute la notion de typage "fort" vs "faible" est problématique.

En tant qu'archétype, Smalltalk est très fortement typé - il toujours déclenchera une exception si une opération entre deux objets est incompatible. Cependant, je soupçonne que peu de personnes sur cette liste appellent Smalltalk une langue fortement typée, car elle est typée dynamiquement.

Je trouve la notion de typage "statique" versus "dynamique" plus utile que "forte" versus "faible". Un langage de type statique a tous les types compris au moment de la compilation, et le programmeur doit déclarer explicitement le cas contraire.

Contraste avec un langage à typage dynamique, où la frappe est effectuée au moment de l'exécution. Il s'agit généralement d'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 à typage dynamique (comme Smalltalk et Ruby), il est plus utile de considérer 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 le 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 puisse 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 pénible dans les langues à typage statique.

0
Jan Steinman

J'aime @ la réponse d'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 langues faiblement typées ne le font pas, elles peuvent donc tenter d'effectuer une opération qui peut ne pas être possible pour un type particulier. Il pense que la façon la plus simple de voir cela est dans une fonction. C++:

void func(string a) {...}

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:

def func(a)
  ...

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.

0
Lubo Antonov