Réponses:
Quelle est la différence entre une langue fortement typée et une langue typée statiquement?
Un langage typé statiquement a un système de type qui est vérifié au moment de la compilation par l'implémentation (un compilateur ou un interprète). La vérification de type rejette certains programmes et les programmes qui réussissent la vérification sont généralement assortis de certaines garanties; par exemple, le compilateur garantit de ne pas utiliser d'instructions arithmétiques entières sur les nombres à virgule flottante.
Il n'y a pas vraiment d'accord sur ce que signifie "fortement typé", bien que la définition la plus largement utilisée dans la littérature professionnelle soit que dans un langage "fortement typé", il n'est pas possible pour le programmeur de contourner les restrictions imposées par le système de type . Ce terme est presque toujours utilisé pour décrire des langages typés statiquement.
L’opposé du type statique est "typé dynamiquement", ce qui signifie que
Par exemple, Lua , un langage typé dynamiquement, a un type de chaîne, un type de nombre et un type booléen, entre autres. Dans Lua, chaque valeur appartient à exactement un type, mais ce n'est pas une exigence pour toutes les langues typées dynamiquement. Dans Lua, il est permis de concaténer deux chaînes, mais il n'est pas permis de concaténer une chaîne et un booléen.
L'opposé de "fortement typé" est "faiblement typé", ce qui signifie que vous pouvez contourner le système de typage. C est notoirement faiblement typé car tout type de pointeur est convertible en tout autre type de pointeur simplement par transtypage. Pascal devait être fortement typé, mais une erreur de conception (enregistrements de variantes non marquées) a introduit une faille dans le système de type, donc techniquement il est faiblement typé. CLU, Standard ML et Haskell sont des exemples de langages vraiment fortement typés. Le standard ML a en fait subi plusieurs révisions pour supprimer les failles du système de type qui ont été découvertes après que le langage ait été largement déployé.
Dans l'ensemble, il s'avère peu utile de parler de «fort» et de «faible». La question de savoir si un système de type a une échappatoire est moins importante que le nombre et la nature exacts des échappatoires, la probabilité qu'ils se présentent en pratique et les conséquences de l'exploitation d'une échappatoire. En pratique, il vaut mieux éviter les termes "fort" et "faible" , car
Les amateurs les confondent souvent avec "statique" et "dynamique".
Apparemment, le «typage faible» est utilisé par certaines personnes pour parler de la prévalence relative ou de l'absence de conversions implicites.
Les professionnels ne peuvent s'entendre sur la signification exacte des termes.
Dans l'ensemble, il est peu probable que vous informiez ou éclairiez votre public.
La triste vérité est que lorsqu'il s'agit de systèmes de types, «fort» et «faible» n'ont pas de signification technique universellement acceptée. Si vous voulez discuter de la force relative des systèmes de type, il est préférable de discuter exactement quelles garanties sont et ne sont pas fournies. Par exemple, une bonne question à poser est la suivante: "est-il garanti que chaque valeur d'un type (ou d'une classe) donnée a été créée en appelant l'un des constructeurs de ce type?" En C, la réponse est non. Dans CLU, F # et Haskell, c'est oui. Pour C ++, je ne suis pas sûr - je voudrais savoir.
En revanche, le typage statique signifie que les programmes sont vérifiés avant d'être exécutés et qu'un programme peut être rejeté avant son démarrage. Le typage dynamique signifie que les types de valeurs sont vérifiés pendant l' exécution et qu'une opération mal typée peut entraîner l'arrêt du programme ou signaler une erreur au moment de l'exécution. Une raison principale du typage statique est d'exclure les programmes qui pourraient avoir de telles "erreurs de type dynamique".
Est-ce que l'un implique l'autre?
Sur un plan pédant, non, car le mot «fort» ne veut vraiment rien dire. Mais dans la pratique, les gens font presque toujours l'une des deux choses suivantes:
Ils utilisent (à tort) «fort» et «faible» pour signifier «statique» et «dynamique», auquel cas ils utilisent (à tort) «fortement typé» et «statiquement typé» de manière interchangeable.
Ils utilisent «fort» et «faible» pour comparer les propriétés des systèmes de type statique. Il est très rare d'entendre quelqu'un parler d'un système de type dynamique "fort" ou "faible". À l'exception de FORTH, qui n'a pas vraiment de système de type, je ne peux pas penser à un langage typé dynamiquement où le système de type peut être subverti. Par définition, ces vérifications sont intégrées dans le moteur d'exécution et chaque opération est vérifiée avant d'être exécutée.
Quoi qu'il en soit, si une personne appelle une langue «fortement typée», cette personne parlera très probablement d'une langue typée statiquement.
C'est souvent mal compris alors permettez-moi de clarifier les choses.
Le typage statique est l'endroit où le type est lié à la variable . Les types sont vérifiés au moment de la compilation.
La frappe dynamique est l'endroit où le type est lié à la valeur . Les types sont vérifiés au moment de l'exécution.
Donc en Java par exemple:
String s = "abcd";
s
sera "pour toujours" un String
. Au cours de sa vie, il peut pointer vers différents String
s (puisqu'il s
s'agit d'une référence en Java). Il peut avoir une null
valeur mais ne fera jamais référence à un Integer
ou à un List
. C'est du typage statique.
En PHP:
$s = "abcd"; // $s is a string
$s = 123; // $s is now an integer
$s = array(1, 2, 3); // $s is now an array
$s = new DOMDocument; // $s is an instance of the DOMDocument class
C'est du typage dynamique.
(Modifier l'alerte!)
La dactylographie forte est une phrase sans signification largement acceptée. La plupart des programmeurs qui utilisent ce terme pour signifier autre chose que le typage statique l'utilisent pour impliquer qu'il existe une discipline de type qui est appliquée par le compilateur. Par exemple, CLU a un système de type fort qui ne permet pas au code client de créer une valeur de type abstrait, sauf en utilisant les constructeurs fournis par le type. C a un système de type assez fort, mais il peut être "subverti" à un degré parce qu'un programme peut toujours convertir une valeur d'un type de pointeur en une valeur d'un autre type de pointeur. Ainsi, par exemple, en C, vous pouvez prendre une valeur renvoyée par malloc()
et la convertir joyeusement enFILE*
, et le compilateur n'essaiera pas de vous arrêter - ni même de vous avertir que vous faites quelque chose de louche.
(La réponse originale disait quelque chose à propos d'une valeur "ne changeant pas de type au moment de l'exécution". J'ai connu de nombreux concepteurs de langage et rédacteurs de compilateurs et je n'en connais aucun qui parlait de valeurs changeant de type au moment de l'exécution, sauf peut-être des recherches très avancées sur le type systèmes, où cela est connu comme le "problème de mise à jour forte".)
Un typage faible implique que le compilateur n'applique pas une discpline de typage, ou peut-être que l'application peut facilement être inversée.
L'original de cette réponse a confondu un typage faible avec une conversion implicite (parfois aussi appelée "promotion implicite"). Par exemple, en Java:
String s = "abc" + 123; // "abc123";
Ce code est un exemple de promotion implicite: 123 est implicitement converti en chaîne avant d'être concaténé avec "abc"
. On peut faire valoir que le compilateur Java réécrit ce code comme:
String s = "abc" + new Integer(123).toString();
Considérez un problème PHP «commence par» classique:
if (strpos('abcdef', 'abc') == false) {
// not found
}
L'erreur ici est que strpos()
renvoie l'index de la correspondance, étant 0. 0 est contraint en booléen false
et donc la condition est réellement vraie. La solution consiste à utiliser ===
au lieu d' ==
éviter la conversion implicite.
Cet exemple illustre comment une combinaison de conversion implicite et de typage dynamique peut égarer les programmeurs.
Comparez cela à Ruby:
val = "abc" + 123
ce qui est une erreur d'exécution car dans Ruby, l' objet 123 n'est pas implicitement converti simplement parce qu'il se trouve être passé à une +
méthode. Dans Ruby, le programmeur doit rendre la conversion explicite:
val = "abc" + 123.to_s
La comparaison de PHP et Ruby en est une bonne illustration. Les deux sont des langages typés dynamiquement mais PHP a beaucoup de conversions implicites et Ruby (peut-être surprenant si vous ne le connaissez pas) ne le fait pas.
Le point ici est que l'axe statique / dynamique est indépendant de l'axe fort / faible. Les gens les confondent probablement en partie parce que le typage fort vs faible n'est pas seulement moins clairement défini, il n'y a pas de véritable consensus sur ce que l'on entend exactement par fort et faible. Pour cette raison, la frappe forte / faible est beaucoup plus une nuance de gris plutôt que de noir ou de blanc.
Donc, pour répondre à votre question: une autre façon de voir cela qui est généralement correct est de dire que le typage statique est une sécurité de type à la compilation et un typage fort est une sécurité de type à l'exécution.
La raison en est que les variables dans un langage de type statique ont un type qui doit être déclaré et peut être vérifié au moment de la compilation. Un langage fortement typé a des valeurs qui ont un type au moment de l'exécution, et il est difficile pour le programmeur de renverser le système de type sans vérification dynamique.
Mais il est important de comprendre qu'un langage peut être statique / fort, statique / faible, dynamique / fort ou dynamique / faible.
"abc" + 123
est une erreur d' exécution , pas une erreur de compilation dans ruby. S'il s'agissait d'une erreur de compilation, ruby serait typé statiquement.
Les deux sont des pôles sur deux axes différents:
Fortement typé , un ne sera pas automatiquement converti d'un type à un autre. Faiblement tapé est le contraire: Perl peut utiliser une chaîne comme"123"
dans un contexte numérique, en la convertissant automatiquement en int 123
. Un langage fortement typé comme python ne le fera pas.
Typiquement , le compilateur détermine le type de chaque variable au moment de la compilation. Les langages typés dynamiquement ne déterminent les types de variables qu'au moment de l'exécution.
Fortement typé signifie qu'il existe des restrictions entre les conversions entre les types. Le typage statique signifie que les types ne sont pas dynamiques - vous ne pouvez pas changer le type d'une variable une fois qu'elle a été créée.
La contrainte de données ne signifie pas nécessairement faiblement typée car parfois son sucre syntaxique:
L'exemple ci-dessus de Java étant faiblement tapé à cause de
String s = "abc" + 123;
N'est pas un exemple faiblement typé car il fait vraiment:
String s = "abc" + new Integer(123).toString()
La coercition des données n'est pas non plus faiblement typée si vous construisez un nouvel objet. Java est un très mauvais exemple de type faiblement typé (et tout langage qui a une bonne réflexion ne sera probablement pas faiblement typé). Parce que le runtime du langage sait toujours quel est le type (l'exception peut être des types natifs).
C'est différent de C. C est l'un des meilleurs exemples de faiblement typé. Le runtime n'a aucune idée si 4 octets est un entier, une structure, un pointeur ou 4 caractères.
Le temps d'exécution du langage définit vraiment s'il est faiblement typé sinon son opinion est vraiment juste.
EDIT: Après mûre réflexion, ce n'est pas nécessairement vrai, car il n'est pas nécessaire que tous les types soient réifiés dans le système d'exécution pour être un système fortement typé. Haskell et ML disposent d'une analyse statique si complète qu'ils peuvent potentiellement ignorer les informations de type à l'exécution.
La réponse est déjà donnée ci-dessus. Essayer de faire la différence entre un concept fort vs semaine et un concept statique vs dynamique.
Fortement typé: ne sera pas automatiquement converti d'un type à un autre
Dans Go ou Python, comme les langages fortement typés, "2" + 8 soulèvera une erreur de type, car ils n'autorisent pas la "contrainte de type".
Faible (vaguement) typé: sera automatiquement converti en un type à un autre: les langages faiblement typés comme JavaScript ou Perl ne génèreront pas d'erreur et dans ce cas, JavaScript produira '28' et perl en produira 10.
Exemple Perl:
my $a = "2" + 8;
print $a,"\n";
Enregistrez-le sur main.pl et exécutez perl main.pl
et vous obtiendrez la sortie 10.
En programmation, le programmeur définit le typage statique et le typage dynamique par rapport au point auquel les types de variables sont vérifiés. Les langages typés statiques sont ceux dans lesquels la vérification de type est effectuée au moment de la compilation, tandis que les langages typés dynamiques sont ceux dans lesquels la vérification de type est effectuée au moment de l'exécution.
Qu'est-ce que cela signifie?
Dans Go, il vérifie tapé avant l'exécution (vérification statique). Cela signifie non seulement qu'il traduit et vérifie le code qu'il exécute, mais qu'il parcourra tout le code et que l'erreur de type serait levée avant même que le code ne soit exécuté. Par exemple,
package main
import "fmt"
func foo(a int) {
if (a > 0) {
fmt.Println("I am feeling lucky (maybe).")
} else {
fmt.Println("2" + 8)
}
}
func main() {
foo(2)
}
Enregistrez ce fichier dans main.go et exécutez-le, vous obtiendrez un message d'échec de compilation pour cela.
go run main.go
# command-line-arguments
./main.go:9:25: cannot convert "2" (type untyped string) to type int
./main.go:9:25: invalid operation: "2" + 8 (mismatched types string and int)
Mais ce cas n'est pas valable pour Python. Par exemple, le bloc de code suivant s'exécutera pour le premier appel foo (2) et échouera pour le deuxième appel foo (0). C'est parce que Python est typé dynamiquement, il ne traduit et ne vérifie que le code sur lequel il s'exécute. Le bloc else ne s'exécute jamais pour foo (2), donc "2" + 8 n'est même jamais regardé et pour foo (0), il essaiera d'exécuter ce bloc et échouera.
def foo(a):
if a > 0:
print 'I am feeling lucky.'
else:
print "2" + 8
foo(2)
foo(0)
Vous verrez la sortie suivante
python main.py
I am feeling lucky.
Traceback (most recent call last):
File "pyth.py", line 7, in <module>
foo(0)
File "pyth.py", line 5, in foo
print "2" + 8
TypeError: cannot concatenate 'str' and 'int' objects
L'un n'implique pas l'autre. Pour qu'un langage soit typé statiquement, cela signifie que les types de toutes les variables sont connus ou déduits au moment de la compilation.
Une langue fortement typée ne vous permet pas d'utiliser un type comme un autre. C est une langue faiblement typée et est un bon exemple de ce que les langues fortement typées ne permettent pas. En C, vous pouvez passer un élément de données du mauvais type et il ne se plaindra pas. Dans les langues fortement typées, vous ne pouvez pas.
Un typage fort signifie probablement que les variables ont un type bien défini et qu'il existe des règles strictes concernant la combinaison de variables de types différents dans les expressions. Par exemple, si A est un entier et B est un flottant, alors la règle stricte concernant A + B pourrait être que A est converti en un flottant et le résultat renvoyé comme un flottant. Si A est un entier et B est une chaîne, alors la règle stricte pourrait être que A + B n'est pas valide.
Le typage statique signifie probablement que les types sont assignés au moment de la compilation (ou son équivalent pour les langages non compilés) et ne peuvent pas changer pendant l'exécution du programme.
Notez que ces classifications ne s'excluent pas mutuellement, en effet je m'attendrais à ce qu'elles se produisent fréquemment ensemble. De nombreuses langues fortement typées sont également typées statiquement.
Et notez que lorsque j'utilise le mot «probablement», c'est parce qu'il n'y a pas de définitions universellement acceptées de ces termes. Comme vous l'avez déjà vu dans les réponses jusqu'à présent.