Qu'est-ce que le type sûr?

Réponses:

247

La sécurité des types signifie que le compilateur validera les types lors de la compilation et générera une erreur si vous essayez d'affecter le mauvais type à une variable.

Quelques exemples simples:

// Fails, Trying to put an integer in a string
String one = 1;
// Also fails.
int foo = "bar";

Cela s'applique également aux arguments de méthode, car vous leur transmettez des types explicites:

int AddTwoNumbers(int a, int b)
{
    return a + b;
}

Si j'ai essayé d'appeler cela en utilisant:

int Sum = AddTwoNumbers(5, "5");

Le compilateur lancerait une erreur, car je passe une chaîne ("5"), et il attend un entier.

Dans une langue mal tapée, comme javascript, je peux faire ce qui suit:

function AddTwoNumbers(a, b)
{
    return a + b;
}

si je l'appelle comme ça:

Sum = AddTwoNumbers(5, "5");

Javascript convertit automatiquement le 5 en une chaîne et renvoie "55". Cela est dû au fait que javascript utilise le signe + pour la concaténation des chaînes. Pour le rendre sensible au type, vous devez faire quelque chose comme:

function AddTwoNumbers(a, b)
{
    return Number(a) + Number(b);
}

Ou, éventuellement:

function AddOnlyTwoNumbers(a, b)
{
    if (isNaN(a) || isNaN(b))
        return false;
    return Number(a) + Number(b);
}

si je l'appelle comme ça:

Sum = AddTwoNumbers(5, " dogs");

Javascript convertit automatiquement le 5 en une chaîne et les ajoute pour renvoyer "5 chiens".

Tous les langages dynamiques ne sont pas aussi indulgents que javascript (En fait, un langage dynamique n'implique pas implicitement un langage typé lâche (voir Python)), certains d'entre eux vous donneront en fait une erreur d'exécution sur la conversion de type invalide.

Bien que cela soit pratique, il vous ouvre de nombreuses erreurs qui peuvent être facilement manquées et uniquement identifiées en testant le programme en cours d'exécution. Personnellement, je préfère que mon compilateur me dise si j'ai fait cette erreur.

Maintenant, revenons à C # ...

C # prend en charge une fonctionnalité de langage appelée covariance , cela signifie essentiellement que vous pouvez remplacer un type de base par un type enfant et ne pas provoquer d'erreur, par exemple:

 public class Foo : Bar
 {
 }

Ici, j'ai créé une nouvelle classe (Foo) qui sous-classe Bar. Je peux maintenant créer une méthode:

 void DoSomething(Bar myBar)

Et appelez-le en utilisant soit un Foo, soit une Bar comme argument, les deux fonctionneront sans provoquer d'erreur. Cela fonctionne car C # sait que toute classe enfant de Bar implémentera l'interface de Bar.

Cependant, vous ne pouvez pas faire l'inverse:

void DoSomething(Foo myFoo)

Dans cette situation, je ne peux pas passer Bar à cette méthode, car le compilateur ne sait pas que Bar implémente l'interface de Foo. En effet, une classe enfant peut (et sera généralement) très différente de la classe parent.

Bien sûr, maintenant je suis allé bien au-delà de l'extrémité profonde et au-delà de la portée de la question d'origine, mais c'est tout bon à savoir :)

FlySwat
la source
26
Je pense que cette réponse est fausse: la sécurité des types n'est pas nécessairement appliquée au moment de la compilation. Je comprends que Scheme, par exemple, est considéré comme sûr pour le type, mais est vérifié dynamiquement (la sécurité du type est appliquée lors de l'exécution). Cela paraphrase principalement l'introduction aux types et langages de programmation, par Benjamin C. Pierce.
Nicolas Rinaudo
11
Ce que vous décrivez s'appelle le polymorphisme, pas la covariance. La covariance est utilisée dans les génériques.
IllidanS4 veut que Monica revienne le
@NicolasRinaudo note que l'écart entre les langages dynamiques et statiques est érodé par la compilation et la précompilation dynamiques pour les langues "interprétées", et par la réflexion dans les langues "compilées". La réflexion permet par exemple de taper du canard à l'exécution, donc un langage compilé peut dire "hé, cela a une méthode Quack (), je l'appellerai et je verrai ce qui se passe". Les langages de type Pascal ont également souvent (en option) une vérification de dépassement de capacité d'exécution, ce qui conduit à des erreurs de "compilateur" qui se produisent au moment de l'exécution "ne peuvent pas adapter l'entier fourni dans la destination 8 bits {core dump}".
Code Abominator
2
Votre exemple fait référence à un concept appelé "fortement typé" qui n'est pas identique à la sécurité de type. La sécurité de type est lorsqu'un langage peut détecter des erreurs de type lors de l'exécution ou de la compilation. Python par exemple est faiblement typé et sûr. Cette réponse doit être signalée car elle est très trompeuse.
dantebarba
explication en général c. bonne, mais la sécurité des caractères n'est pas la même que celle fortement tapée
senseiwu
57

La sécurité de type ne doit pas être confondue avec le typage statique / dynamique ou le typage fort / faible.

Un langage de type sécurisé est celui où les seules opérations que l'on peut exécuter sur des données sont celles qui sont tolérées par le type de données. Autrement dit, si vos données sont de type Xet Xne prennent pas en charge l'opération y, le langage ne vous permettra pas de l'exécuter y(X).

Cette définition ne définit pas de règles lorsque cette case est cochée. Il peut s'agir de la compilation (typage statique) ou de l'exécution (typage dynamique), généralement par le biais d'exceptions. Cela peut être un peu des deux: certains langages typés statiquement vous permettent de convertir des données d'un type à un autre, et la validité des transtypages doit être vérifiée au moment de l'exécution (imaginez que vous essayez de convertir un Objecten un Consumer- le compilateur n'a pas moyen de savoir s’il est acceptable ou non).

La sécurité de type ne signifie pas nécessairement non plus fortement typée - certaines langues sont notoirement faiblement typées, mais peuvent sans doute être sécurisées. Prenons l'exemple de Javascript: son système de type est aussi faible que possible, mais toujours strictement défini. Il permet la conversion automatique des données (par exemple, des chaînes en pouces), mais dans des règles bien définies. Il n'y a à ma connaissance aucun cas où un programme Javascript se comportera de manière indéfinie, et si vous êtes assez intelligent (je ne le suis pas), vous devriez être capable de prédire ce qui se passera lors de la lecture du code Javascript.

Un exemple de langage de programmation non sécurisé de type est C: la lecture / écriture d'une valeur de tableau en dehors des limites du tableau a un comportement non défini par spécification . Il est impossible de prédire ce qui se passera. C est un langage qui a un système de type, mais qui n'est pas sûr pour le type.

Nicolas Rinaudo
la source
1
Quels sont les autres exemples de langages non sécurisés? Que voulez-vous dire par "l'écriture d'une valeur de tableau en dehors des limites du tableau a un comportement indéfini par spécification. Il est impossible de prédire ce qui se passera". Comme Javascript, il renverra un droit non défini? Ou tout peut vraiment arriver. Pouvez-vous en donner un exemple?
ARK
1
@AkshayrajKore, bien sûr. Les tableaux sont des pointeurs de mémoire, donc en écrivant hors des limites, vous pourriez écraser les données d'un autre programme - ce qui ne peut rien faire, planter le programme, le faire effacer votre disque dur - ce n'est pas défini et dépend de qui lit ce morceau de mémoire et comment il y réagira.
Nicolas Rinaudo
@Nicolas Rinaudo Ce n'est pas correct. Vous devriez lire sur la mémoire virtuelle. Chaque processus a son propre espace d'adressage virtuel, de sorte qu'un processus ne peut pas "écraser les données d'un autre programme" de cette manière.
ilstam
Vous avez raison - cela aurait dû lire que vous pourriez écraser une autre partie de la mémoire de votre programme - jusqu'à et y compris, je crois, le programme lui-même?
Nicolas Rinaudo
@NicolasRinaudo Le segment de code du programme est mappé en lecture seule dans l'espace d'adressage virtuel. Donc, si vous essayez d'écrire dessus, cela entraînera une erreur de segmentation et votre programme plantera. De même, si vous essayez d'écrire dans la mémoire non mappée, cela entraînerait une erreur de page et se bloquerait à nouveau. Cependant, si vous n'avez pas de chance, vous pouvez simplement écraser les données de la pile ou du tas du processus (comme d'autres variables ou d'autres choses). Dans ce cas, vous ne planteriez probablement pas immédiatement, ce qui est encore pire parce que vous ne remarquerez pas le bug avant (espérons-le) plus tard!
ilstam
32

La sécurité des types n'est pas seulement une contrainte de temps de compilation, mais une contrainte de temps d'exécution . Je pense que même après tout ce temps, nous pouvons ajouter plus de clarté à cela.

Il existe 2 principaux problèmes liés à la sécurité des types. Mémoire ** et type de données (avec ses opérations correspondantes).

Mémoire**

A charnécessite généralement 1 octet par caractère ou 8 bits (dépend du langage, des caractères unicode du magasin Java et C # qui nécessitent 16 bits). Un intnécessite 4 octets ou 32 bits (généralement).

Visuellement:

char: |-|-|-|-|-|-|-|-|

int : |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|

Un langage de type sécurisé ne permet pas d'insérer un int dans un caractère au moment de l' exécution (cela devrait lever une sorte de transtypage de classe ou une exception de mémoire insuffisante). Cependant, dans un langage de type non sécurisé, vous écraseriez les données existantes dans 3 octets de mémoire adjacents supplémentaires.

int >> char:

|-|-|-|-|-|-|-|-| |?|?|?|?|?|?|?|?| |?|?|?|?|?|?|?|?| |?|?|?|?|?|?|?|?|

Dans le cas ci-dessus, les 3 octets à droite sont remplacés, donc tous les pointeurs vers cette mémoire (disons 3 caractères consécutifs) qui s'attendent à obtenir une valeur de caractère prévisible auront désormais des ordures. Cela provoque un undefinedcomportement dans votre programme (ou pire, peut-être dans d'autres programmes selon la façon dont le système d'exploitation alloue la mémoire - très peu probable de nos jours).

** Bien que ce premier problème ne concerne pas techniquement le type de données, les langues sécurisées de type le traitent de manière inhérente et décrivent visuellement le problème à ceux qui ne savent pas à quoi ressemble l'allocation de mémoire.

Type de données

Le problème de type le plus subtil et le plus direct est celui où deux types de données utilisent la même allocation de mémoire. Prenez un int vs un int non signé. Les deux sont 32 bits. (Tout aussi facilement pourrait être un char [4] et un int, mais le problème le plus courant est uint vs int).

|-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|

|-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|

Un langage de type non sécurisé permet au programmeur de référencer une plage correctement allouée de 32 bits, mais lorsque la valeur d'un entier non signé est lue dans l'espace d'un entier (ou vice versa), nous avons à nouveau un undefinedcomportement. Imaginez les problèmes que cela pourrait causer dans un programme bancaire:

"Mec! J'ai découverts 30 $ et maintenant il me reste 65 506 $ !!"

... 'bien sûr, les programmes bancaires utilisent des types de données beaucoup plus volumineux. ;) LOL!

Comme d'autres l'ont déjà souligné, le problème suivant concerne les opérations de calcul sur les types. Cela a déjà été suffisamment couvert.

Vitesse vs sécurité

Aujourd'hui, la plupart des programmeurs n'ont jamais à se soucier de telles choses à moins qu'ils n'utilisent quelque chose comme C ou C ++. Ces deux langages permettent aux programmeurs de violer facilement la sécurité des types au moment de l'exécution (référencement direct de la mémoire) malgré les meilleurs efforts des compilateurs pour minimiser le risque. CEPENDANT, ce n'est pas si mal.

L'une des raisons pour lesquelles ces langages sont si rapides sur le plan du calcul est qu'ils ne sont pas gênés par la vérification de la compatibilité des types pendant les opérations d'exécution comme, par exemple, Java. Ils supposent que le développeur est un bon être rationnel qui n'ajoutera pas une chaîne et un int ensemble et pour cela, le développeur est récompensé par sa vitesse / efficacité.

Gr3go
la source
27

De nombreuses réponses confondent la sécurité de type avec le typage statique et le typage dynamique. Un langage typé dynamiquement (comme smalltalk) peut également être sûr pour le type.

Une réponse courte: une langue est considérée comme sécurisée si aucune opération n'entraîne un comportement indéfini. Beaucoup considèrent l'exigence de conversions de types explicites nécessaires pour qu'un langage soit strictement typé, car les conversions automatiques peuvent parfois conduire à des comportements bien définis mais inattendus / peu intuitifs.

ididak
la source
1
Attendez, votre définition de type sécurité n'a pas un seul mot « type »: D if no operation leads to undefined behavior.
VasiliNovikov
1
De plus, je ne serais pas d'accord avec une telle définition. Je pense que la sécurité des types signifie exactement 1. l'existence de types 2. la connaissance de ceux-ci pour le compilateur, et des vérifications appropriées bien sûr.
VasiliNovikov
10

Un langage de programmation qui est de type sécurisé signifie les choses suivantes:

  1. Vous ne pouvez pas lire à partir de variables non initialisées
  2. Vous ne pouvez pas indexer des tableaux au-delà de leurs limites
  3. Vous ne pouvez pas effectuer de conversions de type non contrôlées
Kekule
la source
8

Une explication d'une majeure en arts libéraux, pas d'une majeure en science-fiction:

Lorsque les gens disent qu'une langue ou une fonctionnalité de langue est sécurisée, cela signifie que la langue vous empêchera, par exemple, de passer quelque chose qui n'est pas un entier à une logique qui attend un entier.

Par exemple, en C #, je définis une fonction comme:

 void foo(int arg)

Le compilateur m'empêchera alors de faire ceci:

  // call foo
  foo("hello world")

Dans d'autres langages, le compilateur ne m'arrêterait pas (ou il n'y a pas de compilateur ...), donc la chaîne serait passée à la logique et alors probablement quelque chose de mauvais se produira.

Les langages sûrs de type tentent d'en attraper plus au "moment de la compilation".

Sur le côté inférieur, avec les langages de type sûr, lorsque vous avez une chaîne comme "123" et que vous souhaitez l'utiliser comme un int, vous devez écrire plus de code pour convertir la chaîne en int, ou lorsque vous avez un int comme 123 et que vous voulez l'utiliser dans un message comme "La réponse est 123", vous devez écrire plus de code pour le convertir / le convertir en chaîne.

Corey Trager
la source
4
Le major des arts libéraux dirait une explication :) Vous confondez également le typage statique et le typage dynamique.
ididak
1
Arts "libéraux", pas "majeurs".
Corey Trager
5

Pour mieux comprendre, regardez la vidéo ci-dessous qui montre le code en langage sécurisé de type (C #) et NON en langage sécurisé de type (javascript).

http://www.youtube.com/watch?v=Rlw_njQhkxw

Passons maintenant au texte long.

La sécurité de type signifie éviter les erreurs de type. Une erreur de type se produit lorsque le type de données d'un type est attribué à un autre type INSCRIT et que nous obtenons des résultats indésirables.

Par exemple, JavaScript n'est pas un langage sûr de type. Dans le code ci-dessous, «num» est une variable numérique et «str» est une chaîne. Javascript me permet de faire "num + str", maintenant GUESS va faire de l'arithmétique ou de la concaténation.

Maintenant, pour le code ci-dessous, les résultats sont «55», mais le point important est la confusion créée quel type d'opération il fera.

Cela se produit car javascript n'est pas un langage sûr de type. Cela permet de définir un type de données sur l'autre sans restriction.

<script>
var num = 5; // numeric
var str = "5"; // string
var z = num + str; // arthimetic or concat ????
alert(z); // displays  “55”
</script>

C # est un langage sécurisé de type. Il ne permet pas d'attribuer un type de données à un autre type de données. Le code ci-dessous n'autorise pas l'opérateur «+» sur différents types de données.

entrez la description de l'image ici

Shivprasad Koirala
la source
4

Le type sûr signifie que par programme, le type de données pour une variable, une valeur de retour ou un argument doit correspondre à un certain critère.

En pratique, cela signifie que 7 (un type entier) est différent de "7" (un caractère entre guillemets de type chaîne).

PHP, Javascript et les autres langages de script dynamiques sont généralement faiblement typés, en ce sens qu'ils convertiront une (chaîne) "7" en (entier) 7 si vous essayez d'ajouter "7" + 3, bien que vous deviez parfois le faire explicitement (et Javascript utilise le caractère "+" pour la concaténation).

C / C ++ / Java ne comprendra pas cela, ou concaténera le résultat en "73" à la place. La sécurité de type empêche ces types de bogues dans le code en rendant explicite l'exigence de type.

La sécurité de type est très utile. La solution au "7" + 3 ci-dessus serait de taper cast (int) "7" + 3 (égal à 10).

Jared Farrish
la source
3

Concept:

Pour être très simple Type Safe comme les significations, il s'assure que le type de la variable doit être sûr comme

  1. aucun type de données incorrect, par exemple, ne peut pas enregistrer ou initialiser une variable de type chaîne avec un entier
  2. Les index hors limites ne sont pas accessibles
  3. Autoriser uniquement l'emplacement de mémoire spécifique

il s'agit donc de la sécurité des types de stockage en termes de variables.

azizsagi
la source
2

Essayez cette explication sur ...

TypeSafe signifie que les variables sont vérifiées statiquement pour l'affectation appropriée au moment de la compilation. Par exemple, consder une chaîne ou un entier. Ces deux types de données différents ne peuvent pas être attribués de manière croisée (c'est-à-dire que vous ne pouvez pas affecter un entier à une chaîne ni affecter une chaîne à un entier).

Pour les comportements non sécurisés, tenez compte de ceci:

object x = 89;
int y;

si vous essayez de le faire:

y = x;

le compilateur renvoie une erreur qui indique qu'il ne peut pas convertir un System.Object en entier. Vous devez le faire explicitement. Une façon serait:

y = Convert.ToInt32( x );

L'affectation ci-dessus n'est pas sécurisée. Une affectation de type sécurisée est l'endroit où les types peuvent être directement attribués les uns aux autres.

Les collections non sécurisées par types abondent dans ASP.NET (par exemple, les collections d'application, de session et d'affichage). La bonne nouvelle de ces collections est que (en minimisant les considérations de gestion de l'état de plusieurs serveurs), vous pouvez placer à peu près n'importe quel type de données dans l'une des trois collections. La mauvaise nouvelle: comme ces collections ne sont pas sécurisées, vous devrez convertir les valeurs de manière appropriée lorsque vous les récupérez.

Par exemple:

Session[ "x" ] = 34;

fonctionne bien. Mais pour attribuer à nouveau la valeur entière, vous devrez:

int i = Convert.ToInt32( Session[ "x" ] );

Lisez à propos des génériques pour savoir comment cette installation vous aide à implémenter facilement des collections de typesafe.

C # est un langage sécurisé, mais surveillez les articles sur C # 4.0; des possibilités dynamiques intéressantes se profilent (est-ce une bonne chose que C # obtienne essentiellement l'option Strict: Off ... nous verrons).

rp.
la source
Personnellement, je déteste la notation Convert.To, pourquoi n'utilisez-vous pas simplement un cast sûr? Son seul appel de fonction moins sur la pile d'appels ainsi.
FlySwat
2

Type-Safe est un code qui accède uniquement aux emplacements de mémoire auxquels il est autorisé à accéder, et uniquement de manière bien définie et autorisée. Le code de type sécurisé ne peut pas effectuer une opération sur un objet qui n'est pas valide pour cet objet. Les compilateurs de langage C # et VB.NET produisent toujours du code de type sûr, qui est vérifié pour être de type sûr lors de la compilation JIT.

Jonuz
la source
Voulez-vous dire la sécurité de la mémoire?
golopot
1

Le type sûr signifie que l'ensemble des valeurs qui peuvent être attribuées à une variable de programme doit correspondre à des critères bien définis et testables. Les variables de type sécurisé conduisent à des programmes plus robustes car les algorithmes qui manipulent les variables peuvent avoir confiance que la variable ne prendra qu'une seule parmi un ensemble de valeurs bien défini. Le maintien de cette confiance garantit l'intégrité et la qualité des données et du programme.

Pour de nombreuses variables, l'ensemble des valeurs pouvant être affectées à une variable est défini au moment de l'écriture du programme. Par exemple, une variable appelée "couleur" peut être autorisée à prendre les valeurs "rouge", "vert" ou "bleu" et jamais aucune autre valeur. Pour d'autres variables, ces critères peuvent changer au moment de l'exécution. Par exemple, une variable appelée "couleur" peut uniquement être autorisée à prendre des valeurs dans la colonne "nom" d'une table "Couleurs" dans une base de données relationnelle, où "rouge," vert "et" bleu "sont trois valeurs pour "nom" dans la table "Couleurs", mais une autre partie du programme informatique peut être en mesure d'ajouter à cette liste pendant l'exécution du programme, et la variable peut prendre les nouvelles valeurs après leur ajout à la table Couleurs .

De nombreux langages à sécurité de type donnent l'illusion de la "sécurité de type" en insistant sur la définition stricte de types pour les variables et en n'autorisant qu'une variable à se voir attribuer des valeurs du même "type". Il y a quelques problèmes avec cette approche. Par exemple, un programme peut avoir une variable "yearOfBirth" qui est l'année de la naissance d'une personne, et il est tentant de la transtyper en un entier court. Cependant, ce n'est pas un entier court. Cette année, c'est un chiffre inférieur à 2009 et supérieur à -10000. Cependant, cet ensemble augmente de 1 chaque année pendant l'exécution du programme. En faire un "short int" n'est pas suffisant. Ce qui est nécessaire pour sécuriser ce type de variable est une fonction de validation au moment de l'exécution qui garantit que le nombre est toujours supérieur à -10000 et inférieur à l'année civile suivante.

Les langages qui utilisent le typage dynamique (ou typage canard ou typage manifeste) tels que Perl, Python, Ruby, SQLite et Lua n'ont pas la notion de variables typées. Cela oblige le programmeur à écrire une routine de validation au moment de l'exécution pour chaque variable afin de s'assurer qu'elle est correcte ou à supporter les conséquences d'exceptions au moment de l'exécution inexpliquées. D'après mon expérience, les programmeurs dans des langages typés statiquement tels que C, C ++, Java et C # sont souvent endormis en pensant que les types définis statiquement sont tout ce qu'ils doivent faire pour obtenir les avantages de la sécurité des types. Ce n'est tout simplement pas vrai pour de nombreux programmes informatiques utiles, et il est difficile de prédire si cela est vrai pour un programme informatique particulier.

Le long et le court .... Voulez-vous la sécurité de type? Si c'est le cas, écrivez des fonctions d'exécution pour vous assurer que lorsqu'une variable se voit attribuer une valeur, elle est conforme à des critères bien définis. L'inconvénient est que cela rend l'analyse de domaine vraiment difficile pour la plupart des programmes informatiques, car vous devez définir explicitement les critères pour chaque variable de programme.

Jay Godse
la source
2
Les variables Python sont typées ( fortement typées, en fait). Essayez de faire cela, par exemple: "str" ​​+ 1. Vous obtiendrez une erreur. Cependant, les types sont vérifiés au moment de l'exécution, plutôt qu'au moment de la compilation.
mipadi