Was bedeutet "typsicher"?
Was bedeutet "typsicher"?
Antworten:
Typensicherheit bedeutet, dass der Compiler beim Kompilieren Typen überprüft und einen Fehler auslöst, wenn Sie versuchen, einer Variablen den falschen Typ zuzuweisen.
Einige einfache Beispiele:
// Fails, Trying to put an integer in a string
String one = 1;
// Also fails.
int foo = "bar";
Dies gilt auch für Methodenargumente, da Sie ihnen explizite Typen übergeben:
int AddTwoNumbers(int a, int b)
{
return a + b;
}
Wenn ich versuchen würde, das mit zu nennen:
int Sum = AddTwoNumbers(5, "5");
Der Compiler würde einen Fehler auslösen, da ich eine Zeichenfolge ("5") übergebe und eine Ganzzahl erwarte.
In einer lose getippten Sprache wie Javascript kann ich Folgendes tun:
function AddTwoNumbers(a, b)
{
return a + b;
}
wenn ich es so nenne:
Sum = AddTwoNumbers(5, "5");
Javascript konvertiert die 5 automatisch in eine Zeichenfolge und gibt "55" zurück. Dies liegt an Javascript, das das + -Zeichen für die Verkettung von Zeichenfolgen verwendet. Um es typbewusst zu machen, müssten Sie Folgendes tun:
function AddTwoNumbers(a, b)
{
return Number(a) + Number(b);
}
Oder möglicherweise:
function AddOnlyTwoNumbers(a, b)
{
if (isNaN(a) || isNaN(b))
return false;
return Number(a) + Number(b);
}
wenn ich es so nenne:
Sum = AddTwoNumbers(5, " dogs");
Javascript konvertiert die 5 automatisch in eine Zeichenfolge und hängt sie an, um "5 Hunde" zurückzugeben.
Nicht alle dynamischen Sprachen sind so verzeihend wie Javascript (tatsächlich impliziert eine dynamische Sprache nicht implizit eine lose typisierte Sprache (siehe Python)). Einige von ihnen führen tatsächlich zu einem Laufzeitfehler beim Casting ungültiger Typen.
Es ist zwar praktisch, öffnet Ihnen jedoch viele Fehler, die leicht übersehen werden können und nur durch Testen des laufenden Programms identifiziert werden können. Persönlich möchte ich lieber von meinem Compiler erfahren lassen, ob ich diesen Fehler gemacht habe.
Nun zurück zu C # ...
C # unterstützt eine Sprachfunktion namens Kovarianz . Dies bedeutet im Grunde, dass Sie einen Basistyp durch einen untergeordneten Typ ersetzen können, ohne einen Fehler zu verursachen. Beispiel:
public class Foo : Bar
{
}
Hier habe ich eine neue Klasse (Foo) erstellt, die Bar unterordnet. Ich kann jetzt eine Methode erstellen:
void DoSomething(Bar myBar)
Wenn Sie es entweder mit einem Foo oder einem Balken als Argument bezeichnen, funktionieren beide ohne Fehler. Dies funktioniert, weil C # weiß, dass jede untergeordnete Klasse von Bar die Schnittstelle von Bar implementiert.
Sie können jedoch nicht das Gegenteil tun:
void DoSomething(Foo myFoo)
In dieser Situation kann ich Bar nicht an diese Methode übergeben, da der Compiler nicht weiß, dass Bar die Schnittstelle von Foo implementiert. Dies liegt daran, dass eine untergeordnete Klasse sich stark von der übergeordneten Klasse unterscheiden kann (und dies normalerweise auch tun wird).
Natürlich bin ich jetzt weit vom Ende entfernt und habe den Rahmen der ursprünglichen Frage überschritten, aber es ist alles gut zu wissen :)
Die Typensicherheit sollte nicht mit statischer / dynamischer oder starker / schwacher Typisierung verwechselt werden.
Eine typsichere Sprache ist eine Sprache, in der die einzigen Operationen, die für Daten ausgeführt werden können, diejenigen sind, die vom Datentyp geduldet werden. Das heißt, wenn Ihre Daten vom Typ sind X
und den X
Betrieb nicht unterstützen y
, können Sie sie in der Sprache nicht ausführen y(X)
.
Diese Definition legt keine Regeln fest, wenn dies aktiviert ist. Dies kann zur Kompilierungszeit (statische Typisierung) oder zur Laufzeit (dynamische Typisierung) erfolgen, normalerweise durch Ausnahmen. Es kann ein bisschen von beidem sein: In einigen statisch typisierten Sprachen können Sie Daten von einem Typ in einen anderen umwandeln, und die Gültigkeit von Casts muss zur Laufzeit überprüft werden (stellen Sie sich vor, Sie versuchen, einen Object
in einen Consumer
umzuwandeln - der Compiler hat keine Art zu wissen, ob es akzeptabel ist oder nicht).
Typensicherheit bedeutet auch nicht unbedingt stark typisiert - einige Sprachen sind notorisch schwach typisiert, aber dennoch typsicher. Nehmen wir zum Beispiel Javascript: Das Typensystem ist so schwach wie es kommt, aber immer noch streng definiert. Es ermöglicht das automatische Umwandeln von Daten (z. B. Zeichenfolgen in Ints), jedoch innerhalb genau definierter Regeln. Meines Wissens gibt es keinen Fall, in dem sich ein Javascript-Programm undefiniert verhält, und wenn Sie klug genug sind (ich nicht), sollten Sie vorhersagen können, was beim Lesen von Javascript-Code passieren wird.
Ein Beispiel für eine typsichere Programmiersprache ist C: Das Lesen / Schreiben eines Array-Werts außerhalb der Grenzen des Arrays weist nach Spezifikation ein undefiniertes Verhalten auf . Es ist unmöglich vorherzusagen, was passieren wird. C ist eine Sprache mit einem Typsystem, die jedoch nicht typsicher ist.
Die Typensicherheit ist nicht nur eine Einschränkung der Kompilierungszeit, sondern auch eine Laufzeitbeschränkung . Ich bin der Meinung, dass wir auch nach all dieser Zeit noch mehr Klarheit schaffen können.
Es gibt zwei Hauptprobleme im Zusammenhang mit der Typensicherheit. Speicher ** und Datentyp (mit den entsprechenden Operationen).
A char
benötigt normalerweise 1 Byte pro Zeichen oder 8 Bit (abhängig von Sprache, Java und C # speichern Unicode-Zeichen, die 16 Bit erfordern). A int
benötigt 4 Bytes oder 32 Bit (normalerweise).
Visuell:
char: |-|-|-|-|-|-|-|-|
int : |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|
In einer typsicheren Sprache kann ein int zur Laufzeit nicht in ein Zeichen eingefügt werden (dies sollte eine Art Klassenumwandlung oder eine Ausnahme wegen Speichermangel auslösen). In einer unsicheren Sprache würden Sie jedoch vorhandene Daten in drei weiteren benachbarten Speicherbytes überschreiben.
int >> char:
|-|-|-|-|-|-|-|-| |?|?|?|?|?|?|?|?| |?|?|?|?|?|?|?|?| |?|?|?|?|?|?|?|?|
Im obigen Fall werden die 3 Bytes rechts überschrieben, sodass alle Zeiger auf diesen Speicher (z. B. 3 aufeinanderfolgende Zeichen), die einen vorhersagbaren Zeichenwert erwarten, jetzt Müll enthalten. Dies führt zu undefined
Verhalten in Ihrem Programm (oder schlimmer noch, möglicherweise in anderen Programmen, je nachdem, wie das Betriebssystem Speicher zuweist - heutzutage sehr unwahrscheinlich).
** Während es in dieser ersten Ausgabe technisch nicht um den Datentyp geht, wird er von sicheren Sprachen inhärent behandelt und das Problem wird denjenigen visuell beschrieben, die nicht wissen, wie die Speicherzuweisung "aussieht".
Das subtilere und direktere Typproblem besteht darin, dass zwei Datentypen dieselbe Speicherzuordnung verwenden. Nehmen Sie ein int gegen ein vorzeichenloses int. Beide sind 32 Bit. (Genauso leicht könnte ein char [4] und ein int sein, aber das häufigere Problem ist uint vs. int).
|-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|
|-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|
Eine unsichere Sprache ermöglicht es dem Programmierer, auf eine ordnungsgemäß zugewiesene Spanne von 32 Bit zu verweisen. Wenn jedoch der Wert eines vorzeichenlosen int in den Raum eines int eingelesen wird (oder umgekehrt), tritt erneut ein undefined
Verhalten auf. Stellen Sie sich die Probleme vor, die dies in einem Bankprogramm verursachen könnte:
"Alter! Ich habe 30 $ überzogen und jetzt habe ich noch 65.506 $ übrig !!"
... Natürlich verwenden Bankprogramme viel größere Datentypen. ;) LOL!
Wie andere bereits betont haben, besteht das nächste Problem in Rechenoperationen für Typen. Das wurde bereits ausreichend abgedeckt.
Die meisten Programmierer müssen sich heutzutage nie um solche Dinge kümmern, es sei denn, sie verwenden etwas wie C oder C ++. Beide Sprachen ermöglichen es Programmierern, die Typensicherheit zur Laufzeit leicht zu verletzen (direkte Speicherreferenzierung), obwohl die Compiler sich nach besten Kräften bemühen, das Risiko zu minimieren. Das ist jedoch nicht alles schlecht.
Ein Grund dafür, dass diese Sprachen so rechenschnell sind, besteht darin, dass sie nicht durch die Überprüfung der Typkompatibilität während Laufzeitvorgängen wie beispielsweise Java belastet werden. Sie gehen davon aus, dass der Entwickler ein gutes rationales Wesen ist, das keinen String und kein Int zusammenfügt, und dafür wird der Entwickler mit Geschwindigkeit / Effizienz belohnt.
Viele Antworten verbinden hier Typensicherheit mit statischer und dynamischer Typisierung. Eine dynamisch typisierte Sprache (wie Smalltalk) kann ebenfalls typsicher sein.
Eine kurze Antwort: Eine Sprache gilt als typsicher, wenn keine Operation zu undefiniertem Verhalten führt. Viele halten die Anforderung expliziter Typkonvertierungen für erforderlich, damit eine Sprache streng typisiert werden kann, da automatische Konvertierungen manchmal zu genau definierten, aber unerwarteten / nicht intuitiven Verhaltensweisen führen können.
if no operation leads to undefined behavior
.
Eine Erklärung von einem Hauptfach für freie Künste, nicht von einem Hauptfach für Comp Sci Sci:
Wenn Leute sagen, dass eine Sprache oder ein Sprachmerkmal typsicher ist, bedeutet dies, dass die Sprache Sie daran hindert, beispielsweise etwas, das keine Ganzzahl ist, an eine Logik zu übergeben, die eine Ganzzahl erwartet.
Zum Beispiel definiere ich in C # eine Funktion als:
void foo(int arg)
Der Compiler wird mich dann davon abhalten:
// call foo
foo("hello world")
In anderen Sprachen würde mich der Compiler nicht aufhalten (oder es gibt keinen Compiler ...), so dass die Zeichenfolge an die Logik übergeben würde und dann wahrscheinlich etwas Schlimmes passieren würde.
Typensichere Sprachen versuchen, zur "Kompilierungszeit" mehr zu fangen.
Auf der anderen Seite müssen Sie bei typsicheren Sprachen, wenn Sie eine Zeichenfolge wie "123" haben und diese wie eine int bearbeiten möchten, mehr Code schreiben, um die Zeichenfolge in eine int zu konvertieren, oder wenn Sie eine int haben Wie 123 und wenn Sie es in einer Nachricht wie "Die Antwort ist 123" verwenden möchten, müssen Sie mehr Code schreiben, um es in eine Zeichenfolge zu konvertieren / umzuwandeln.
Um ein besseres Verständnis zu erhalten, sehen Sie sich das folgende Video an, in dem Code in typsicherer Sprache (C #) und NICHT in typensicherer Sprache (Javascript) gezeigt wird.
http://www.youtube.com/watch?v=Rlw_njQhkxw
Nun zum langen Text.
Typensicherheit bedeutet, Typfehler zu vermeiden. Ein Typfehler tritt auf, wenn der Datentyp eines Typs UNBEKANNT einem anderen Typ zugewiesen wird und wir unerwünschte Ergebnisse erhalten.
Zum Beispiel ist JavaScript KEINE typsichere Sprache. Im folgenden Code ist "num" eine numerische Variable und "str" eine Zeichenfolge. Mit Javascript kann ich "num + str" machen, jetzt wird es wohl rechnen oder verketten.
Für den folgenden Code sind die Ergebnisse "55", aber der wichtige Punkt ist die Verwirrung darüber, welche Art von Operation er ausführen wird.
Dies geschieht, weil Javascript keine typsichere Sprache ist. Es erlaubt, einen Datentyp ohne Einschränkungen auf den anderen Typ zu setzen.
<script>
var num = 5; // numeric
var str = "5"; // string
var z = num + str; // arthimetic or concat ????
alert(z); // displays “55”
</script>
C # ist eine typsichere Sprache. Es ist nicht möglich, einen Datentyp einem anderen Datentyp zuzuweisen. Der folgende Code erlaubt keinen "+" - Operator für verschiedene Datentypen.
Typensicher bedeutet, dass programmgesteuert der Datentyp für eine Variable, einen Rückgabewert oder ein Argument einem bestimmten Kriterium entsprechen muss.
In der Praxis bedeutet dies, dass 7 (ein ganzzahliger Typ) sich von "7" (ein Anführungszeichen vom Typ "Zeichenfolge") unterscheidet.
PHP, Javascript und andere dynamische Skriptsprachen sind normalerweise schwach typisiert, da sie eine (Zeichenfolge) "7" in eine (Ganzzahl) 7 konvertieren, wenn Sie versuchen, "7" + 3 hinzuzufügen, obwohl Sie dies manchmal tun müssen explizit (und Javascript verwendet das Zeichen "+" zur Verkettung).
C / C ++ / Java wird das nicht verstehen oder das Ergebnis stattdessen in "73" verketten. Die Typensicherheit verhindert diese Art von Fehlern im Code, indem die Typanforderung explizit angegeben wird.
Typensicherheit ist sehr nützlich. Die Lösung für die obige "7" + 3 wäre, cast (int) "7" + 3 (gleich 10) einzugeben.
Konzept:
Um sehr einfach zu sein, geben Sie sicher wie die Bedeutungen ein, dass der Typ der Variablen sicher sein sollte
Es geht also um die Sicherheit der Speichertypen in Bezug auf Variablen.
Versuchen Sie diese Erklärung auf ...
TypeSafe bedeutet, dass Variablen beim Kompilieren statisch auf entsprechende Zuordnung überprüft werden. Betrachten Sie beispielsweise eine Zeichenfolge oder eine Ganzzahl. Diese beiden unterschiedlichen Datentypen können nicht übergreifend zugewiesen werden (dh Sie können einer Zeichenfolge weder eine Ganzzahl noch einer Ganzzahl eine Zeichenfolge zuweisen).
Beachten Sie bei nicht typsicherem Verhalten Folgendes:
object x = 89;
int y;
Wenn Sie dies versuchen:
y = x;
Der Compiler gibt einen Fehler aus, der besagt, dass ein System.Object nicht in eine Ganzzahl konvertiert werden kann. Sie müssen dies explizit tun. Ein Weg wäre:
y = Convert.ToInt32( x );
Die obige Zuordnung ist nicht typsicher. Bei einer typsicheren Zuordnung können die Typen direkt einander zugewiesen werden.
Nicht typsichere Sammlungen sind in ASP.NET im Überfluss vorhanden (z. B. die Sammlungen für Anwendungen, Sitzungen und Ansichtszustände). Die gute Nachricht zu diesen Sammlungen ist, dass Sie (unter Minimierung mehrerer Überlegungen zur Verwaltung des Serverstatus) so gut wie jeden Datentyp in eine der drei Sammlungen einfügen können. Die schlechte Nachricht: Da diese Sammlungen nicht typsicher sind, müssen Sie die Werte entsprechend umwandeln, wenn Sie sie wieder herausholen.
Beispielsweise:
Session[ "x" ] = 34;
funktioniert gut. Um den ganzzahligen Wert zurückzugeben, müssen Sie jedoch:
int i = Convert.ToInt32( Session[ "x" ] );
Lesen Sie mehr über Generika, wie Sie mit dieser Funktion typsichere Sammlungen einfach implementieren können.
C # ist eine typsichere Sprache, achten Sie jedoch auf Artikel zu C # 4.0. Es ergeben sich interessante dynamische Möglichkeiten (ist es gut, dass C # im Wesentlichen Option Strict: Off erhält ... wir werden sehen).
Type-Safe ist Code, der nur auf die Speicherorte zugreift, auf die er zugreifen darf, und zwar nur auf genau definierte, zulässige Weise. Typensicherer Code kann keine Operation für ein Objekt ausführen, das für dieses Objekt ungültig ist. Die Sprachcompiler C # und VB.NET erzeugen immer typsicheren Code, der während der JIT-Kompilierung als typsicher überprüft wird.
Typensicher bedeutet, dass der Wertesatz, der einer Programmvariablen zugewiesen werden kann, genau definierten und überprüfbaren Kriterien entsprechen muss. Typensichere Variablen führen zu robusteren Programmen, da die Algorithmen, die die Variablen manipulieren, darauf vertrauen können, dass die Variable nur einen genau definierten Wertesatz annimmt. Durch die Wahrung dieses Vertrauens wird die Integrität und Qualität der Daten und des Programms sichergestellt.
Für viele Variablen wird der Wertesatz, der einer Variablen zugewiesen werden kann, zum Zeitpunkt des Programmschreibens definiert. Beispielsweise kann eine Variable namens "Farbe" die Werte "Rot", "Grün" oder "Blau" annehmen und niemals andere Werte. Für andere Variablen können sich diese Kriterien zur Laufzeit ändern. Beispielsweise darf eine Variable mit dem Namen "Farbe" möglicherweise nur Werte in der Spalte "Name" einer Tabelle "Farben" in einer relationalen Datenbank annehmen, wobei "Rot", "Grün" und "Blau" drei Werte sind für "Name" in der Tabelle "Farben", aber ein anderer Teil des Computerprogramms kann möglicherweise zu dieser Liste hinzufügen, während das Programm ausgeführt wird, und die Variable kann die neuen Werte annehmen, nachdem sie zur Tabelle "Farben" hinzugefügt wurden .
Viele typsichere Sprachen geben die Illusion von "Typensicherheit", indem sie darauf bestehen, Typen für Variablen streng zu definieren und nur zuzulassen, dass einer Variablen Werte desselben "Typs" zugewiesen werden. Bei diesem Ansatz gibt es einige Probleme. Beispielsweise kann ein Programm eine Variable "yearOfBirth" haben, die das Jahr darstellt, in dem eine Person geboren wurde, und es ist verlockend, sie als kurze Ganzzahl einzugeben. Es ist jedoch keine kurze Ganzzahl. In diesem Jahr ist es eine Zahl, die kleiner als 2009 und größer als -10000 ist. Dieser Satz wächst jedoch jedes Jahr um 1, wenn das Programm ausgeführt wird. Es ist nicht ausreichend, dies zu einem "kurzen Int" zu machen. Um diese Variable typsicher zu machen, ist eine Laufzeitvalidierungsfunktion erforderlich, die sicherstellt, dass die Anzahl immer größer als -10000 und kleiner als das nächste Kalenderjahr ist.
Sprachen wie Perl, Python, Ruby, SQLite und Lua, die dynamische Typisierung (oder Enten-Typisierung oder Manifest-Typisierung) verwenden, haben keine Vorstellung von typisierten Variablen. Dies zwingt den Programmierer, für jede Variable eine Laufzeitvalidierungsroutine zu schreiben, um sicherzustellen, dass sie korrekt ist, oder um die Folgen unerklärlicher Laufzeitausnahmen zu ertragen. Nach meiner Erfahrung denken Programmierer in statisch typisierten Sprachen wie C, C ++, Java und C # oft, dass statisch definierte Typen alles sind, was sie tun müssen, um die Vorteile der Typensicherheit zu nutzen. Dies gilt einfach nicht für viele nützliche Computerprogramme, und es ist schwer vorherzusagen, ob dies für ein bestimmtes Computerprogramm zutrifft.
Die langen und die kurzen ... Wollen Sie Typensicherheit? Wenn ja, schreiben Sie Laufzeitfunktionen, um sicherzustellen, dass eine Variable, der ein Wert zugewiesen wurde, genau definierten Kriterien entspricht. Der Nachteil ist, dass die Domänenanalyse für die meisten Computerprogramme sehr schwierig ist, da Sie die Kriterien für jede Programmvariable explizit definieren müssen.