Ich höre viel, dass neue Programmiersprachen dynamisch typisiert werden, aber was bedeutet es eigentlich, wenn wir sagen, dass eine Sprache dynamisch oder statisch typisiert ist?
Ich höre viel, dass neue Programmiersprachen dynamisch typisiert werden, aber was bedeutet es eigentlich, wenn wir sagen, dass eine Sprache dynamisch oder statisch typisiert ist?
Antworten:
Eine Sprache wird statisch typisiert, wenn der Typ einer Variablen zur Kompilierungszeit bekannt ist. Für einige Sprachen bedeutet dies, dass Sie als Programmierer angeben müssen, um welchen Typ es sich bei jeder Variablen handelt (z. B. Java, C, C ++). Andere Sprachen bieten eine Form der Typinferenz , die Fähigkeit des Typsystems, den Typ einer Variablen abzuleiten (z. B. OCaml, Haskell, Scala, Kotlin).
Der Hauptvorteil hierbei ist, dass alle Arten von Überprüfungen vom Compiler durchgeführt werden können und daher viele triviale Fehler sehr früh erkannt werden.
Beispiele: C, C ++, Java, Rust, Go, Scala
Eine Sprache wird dynamisch typisiert, wenn der Typ Laufzeitwerten zugeordnet ist und keine benannten Variablen / Felder / etc. Dies bedeutet, dass Sie als Programmierer etwas schneller schreiben können, da Sie nicht jedes Mal Typen angeben müssen (es sei denn, Sie verwenden eine statisch typisierte Sprache mit Typinferenz ).
Beispiele: Perl, Ruby, Python, PHP, JavaScript
Die meisten Skriptsprachen verfügen über diese Funktion, da ohnehin kein Compiler für die statische Typprüfung vorhanden ist. Möglicherweise suchen Sie jedoch nach einem Fehler, der darauf zurückzuführen ist, dass der Interpreter den Typ einer Variablen falsch interpretiert. Glücklicherweise sind Skripte in der Regel klein, sodass Fehler nicht so viele Orte zum Verstecken haben.
In den meisten dynamisch typisierten Sprachen können Sie Typinformationen bereitstellen, benötigen diese jedoch nicht. Eine Sprache, die derzeit entwickelt wird, Rascal , verfolgt einen hybriden Ansatz, der eine dynamische Typisierung innerhalb von Funktionen ermöglicht, aber eine statische Typisierung für die Funktionssignatur erzwingt.
Statisch typisierte Programmiersprachen tun Typprüfung (dh den Prozess der Überprüfung und die Zwänge der Typen Durchsetzung) bei der Kompilierung Zeit im Gegensatz zu Zeit laufen .
Dynamisch typisierte Programmiersprachen führen zur Laufzeit eine Typprüfung durch und nicht zur Kompilierungszeit .
Beispiele für statisch typisierte Sprachen sind: - Java, C, C ++
Beispiele für dynamisch typisierte Sprachen sind: - Perl, Ruby, Python, PHP, JavaScript
Hier ist ein Beispiel, das gegenüberstellt, wie Python (dynamisch typisiert) und Go (statisch typisiert) einen Typfehler behandeln:
def silly(a):
if a > 0:
print 'Hi'
else:
print 5 + '3'
Python führt zur Laufzeit eine Typprüfung durch und daher:
silly(2)
Läuft einwandfrei und erzeugt die erwartete Ausgabe Hi
. Der Fehler wird nur ausgelöst, wenn die problematische Linie getroffen wird:
silly(-1)
Produziert
TypeError: unsupported operand type(s) for +: 'int' and 'str'
weil die entsprechende Zeile tatsächlich ausgeführt wurde.
Go hingegen führt zur Kompilierungszeit eine Typprüfung durch:
package main
import ("fmt"
)
func silly(a int) {
if (a > 0) {
fmt.Println("Hi")
} else {
fmt.Println("3" + 5)
}
}
func main() {
silly(2)
}
Das oben Gesagte wird mit folgendem Fehler nicht kompiliert:
invalid operation: "3" + 5 (mismatched types string and int)
runhaskell
zum Beispiel mit interpretiert werden .
Einfach ausgedrückt: In einer statisch typisierten Sprache sind die Variablentypen statisch . Wenn Sie also eine Variable auf einen Typ festgelegt haben, können Sie sie nicht mehr ändern. Dies liegt daran, dass die Eingabe eher der Variablen als dem Wert zugeordnet ist, auf den sie sich bezieht.
Zum Beispiel in Java:
String str = "Hello"; //variable str statically typed as string
str = 5; //would throw an error since str is supposed to be a string only
Wo andererseits: In einer dynamisch typisierten Sprache sind die Variablentypen dynamisch , dh nachdem Sie eine Variable auf einen Typ festgelegt haben, können Sie sie ändern. Dies liegt daran, dass die Eingabe eher dem angenommenen Wert als der Variablen selbst zugeordnet ist.
Zum Beispiel in Python:
str = "Hello" # variable str is linked to a string value
str = 5 # now it is linked to an integer value; perfectly OK
Daher ist es am besten, sich Variablen in dynamisch typisierten Sprachen als generische Zeiger auf typisierte Werte vorzustellen.
Um es zusammenzufassen, Typ beschreibt (oder sollte beschrieben haben) , um die Variablen in der Sprache eher als die Sprache selbst. Es könnte besser als verwendet wurde , eine Sprache mit statisch typisierten Variablen im Vergleich zu einer Sprache mit dynamisch typisierten Variablen IMHO.
Statisch typisierte Sprachen sind in der Regel kompilierte Sprachen. Daher überprüfen die Compiler die Typen (sinnvoll, da Typen später zur Laufzeit nicht mehr geändert werden dürfen).
Dynamisch typisierte Sprachen werden im Allgemeinen interpretiert, sodass die Typprüfung (falls vorhanden) zur Laufzeit erfolgt, wenn sie verwendet werden. Dies bringt natürlich einige Leistungskosten mit sich und ist einer der Gründe, warum dynamische Sprachen (z. B. Python, Ruby, PHP) nicht so gut skaliert werden wie die eingegebenen (Java, C # usw.). Aus einer anderen Perspektive haben statisch typisierte Sprachen höhere Startkosten: Sie schreiben normalerweise mehr Code, härteren Code. Aber das zahlt sich später aus.
Das Gute ist, dass beide Seiten Features von der anderen Seite ausleihen. Typisierte Sprachen enthalten dynamischere Funktionen, z. B. Generika und dynamische Bibliotheken in c #, und dynamische Sprachen enthalten mehr Typprüfungen, z. B. Typanmerkungen in Python oder die HACK-Variante von PHP, die normalerweise nicht zum Kern der Sprache gehören und auf der sie verwendet werden können Nachfrage.
Bei der Auswahl der Technologie hat keine Seite eine intrinsische Überlegenheit gegenüber der anderen. Es ist nur eine Frage der Präferenz, ob Sie zunächst mehr Kontrolle oder Flexibilität wünschen. Wählen Sie einfach das richtige Werkzeug für den Job aus und prüfen Sie, was im Gegenteil verfügbar ist, bevor Sie einen Wechsel in Betracht ziehen.
http://en.wikipedia.org/wiki/Type_system
Statische Eingabe
Eine Programmiersprache soll statische Typisierung verwenden, wenn die Typprüfung während der Kompilierungszeit und nicht zur Laufzeit durchgeführt wird. Bei der statischen Typisierung werden Typen Variablen und nicht Werten zugeordnet. Statisch typisierte Sprachen umfassen Ada, C, C ++, C #, JADE, Java, Fortran, Haskell, ML, Pascal, Perl (in Bezug auf die Unterscheidung von Skalaren, Arrays, Hashes und Subroutinen) und Scala. Die statische Typisierung ist eine eingeschränkte Form der Programmüberprüfung (siehe Typensicherheit): Dementsprechend können viele Typfehler früh im Entwicklungszyklus erkannt werden. Statische Typprüfungen werten nur die Typinformationen aus, die zur Kompilierungszeit ermittelt werden können, können jedoch überprüfen, ob die überprüften Bedingungen für alle möglichen Programmausführungen gelten. Dadurch müssen die Typprüfungen nicht jedes Mal wiederholt werden, wenn das Programm ausgeführt wird. Die Programmausführung kann auch effizienter gestaltet werden (dh schneller sein oder weniger Speicher beanspruchen), indem Laufzeitprüfungen weggelassen und andere Optimierungen aktiviert werden.
Da sie Typinformationen während der Kompilierung auswerten und daher Typinformationen fehlen, die nur zur Laufzeit verfügbar sind, sind statische Typprüfungen konservativ. Sie lehnen einige Programme ab, die sich zur Laufzeit möglicherweise gut verhalten, aber statisch nicht als gut typisiert eingestuft werden können. Selbst wenn ein Ausdruck zur Laufzeit immer als wahr ausgewertet wird, enthält ein Programm beispielsweise den Code
if <complex test> then 42 else <type error>
wird als schlecht typisiert abgelehnt, da eine statische Analyse nicht feststellen kann, dass der else-Zweig nicht verwendet wird. [1] Das konservative Verhalten von statischen Typprüfern ist vorteilhaft, wenn sie selten als falsch ausgewertet werden: Ein statischer Typprüfer kann Typfehler in selten verwendeten Codepfaden erkennen. Ohne statische Typprüfung können selbst Codeabdeckungstests mit 100% Codeabdeckung solche Typfehler möglicherweise nicht finden. Code-Coverage-Tests können solche Typfehler möglicherweise nicht erkennen, da die Kombination aller Orte, an denen Werte erstellt werden, und aller Orte, an denen ein bestimmter Wert verwendet wird, berücksichtigt werden muss.
Die am häufigsten verwendeten statisch typisierten Sprachen sind formal nicht typsicher. Sie haben "Lücken" in der Programmiersprachen-Spezifikation, die es Programmierern ermöglichen, Code zu schreiben, der die von einem statischen Typprüfer durchgeführte Überprüfung umgeht und so ein breiteres Spektrum von Problemen angeht. Beispielsweise verfügen Java und die meisten Sprachen im C-Stil über Typ-Punning, und Haskell verfügt über Funktionen wie unsafePerformIO: Solche Vorgänge können zur Laufzeit unsicher sein, da sie aufgrund der falschen Eingabe von Werten beim Ausführen des Programms zu unerwünschtem Verhalten führen können.
Dynamische Eingabe
Eine Programmiersprache wird als dynamisch typisiert oder nur als "dynamisch" bezeichnet, wenn der Großteil ihrer Typprüfung zur Laufzeit und nicht zur Kompilierungszeit durchgeführt wird. Bei der dynamischen Typisierung werden Typen Werten und nicht Variablen zugeordnet. Zu den dynamisch typisierten Sprachen gehören Groovy, JavaScript, Lisp, Lua, Objective-C, Perl (in Bezug auf benutzerdefinierte Typen, jedoch keine integrierten Typen), PHP, Prolog, Python, Ruby, Smalltalk und Tcl. Im Vergleich zur statischen Typisierung kann die dynamische Typisierung flexibler sein (z. B. indem Programme Typen und Funktionen basierend auf Laufzeitdaten generieren können), allerdings auf Kosten weniger a priori Garantien. Dies liegt daran, dass eine dynamisch typisierte Sprache einige Programme akzeptiert und versucht, diese auszuführen, die möglicherweise von einer statischen Typprüfung als ungültig eingestuft werden.
Dynamische Typisierung kann zu Laufzeittypfehlern führen. Das heißt, zur Laufzeit kann ein Wert einen unerwarteten Typ haben, und eine für diesen Typ unsinnige Operation wird angewendet. Dieser Vorgang kann lange nach dem Ort erfolgen, an dem der Programmierfehler gemacht wurde, dh an dem Ort, an dem der falsche Datentyp an einen Ort übergeben wurde, den er nicht haben sollte. Dies macht es schwierig, den Fehler zu finden.
Dynamisch typisierte Sprachsysteme führen im Vergleich zu ihren statisch typisierten Cousins weniger Überprüfungen des Quellcodes zur Kompilierungszeit durch (prüfen jedoch beispielsweise, ob das Programm syntaktisch korrekt ist). Laufzeitprüfungen können möglicherweise komplexer sein, da sie dynamische Informationen sowie alle Informationen verwenden können, die während der Kompilierung vorhanden waren. Andererseits bestätigen Laufzeitprüfungen nur, dass Bedingungen für eine bestimmte Ausführung des Programms gelten, und diese Prüfungen werden für jede Ausführung des Programms wiederholt.
Die Entwicklung in dynamisch typisierten Sprachen wird häufig durch Programmierpraktiken wie Unit-Tests unterstützt. Testen ist eine Schlüsselpraxis in der professionellen Softwareentwicklung und besonders wichtig in dynamisch typisierten Sprachen. In der Praxis können die Tests, die durchgeführt werden, um einen korrekten Programmbetrieb sicherzustellen, einen viel größeren Bereich von Fehlern erkennen als die statische Typprüfung, können jedoch nicht so umfassend nach Fehlern suchen, die sowohl beim Testen als auch bei der statischen Typprüfung erkannt werden können. Das Testen kann in den Software-Erstellungszyklus integriert werden. In diesem Fall kann dies als "Kompilierungszeit" -Prüfung angesehen werden, da der Programmbenutzer solche Tests nicht manuell ausführen muss.
Verweise
- Pierce, Benjamin (2002). Typen und Programmiersprachen. MIT Press. ISBN 0-262-16209-1.
myObject[remoteDataName]
. Dann gibt es keine Möglichkeit zu wissen, welche Eigenschaft ausgewählt wird oder ob es sich überhaupt um eine gültige Eigenschaft handelt.
Die Terminologie "dynamisch typisiert" ist leider irreführend. Alle Sprachen sind statisch typisiert, und Typen sind Eigenschaften von Ausdrücken (nicht von Werten, wie manche denken). Einige Sprachen haben jedoch nur einen Typ. Diese werden als uni-typisierte Sprachen bezeichnet. Ein Beispiel für eine solche Sprache ist der untypisierte Lambda-Kalkül.
In der untypisierten Lambda-Rechnung sind alle Terme Lambda-Terme, und die einzige Operation, die für einen Term ausgeführt werden kann, besteht darin, ihn auf einen anderen Term anzuwenden. Daher führen alle Operationen immer entweder zu einer unendlichen Rekursion oder zu einem Lambda-Term, signalisieren jedoch niemals einen Fehler.
Wenn wir jedoch den untypisierten Lambda-Kalkül mit primitiven Zahlen und arithmetischen Operationen erweitern würden, könnten wir unsinnige Operationen ausführen, indem wir zwei Lambda-Terme addieren : (λx.x) + (λy.y)
. Man könnte argumentieren, dass das einzig Vernünftige darin besteht, einen Fehler zu signalisieren, wenn dies geschieht. Um dies jedoch tun zu können, muss jeder Wert mit einem Indikator versehen werden, der angibt, ob der Begriff ein Lambda-Begriff oder eine Zahl ist. Der Additionsoperator prüft dann, ob tatsächlich beide Argumente als Zahlen gekennzeichnet sind, und signalisiert einen Fehler, wenn dies nicht der Fall ist. Beachten Sie, dass diese Tags keine Typen sind, da Typen Eigenschaften von Programmen sind, nicht von Werten, die von diesen Programmen erzeugt werden.
Eine einheitliche Sprache, die dies tut, wird als dynamisch typisiert bezeichnet.
Sprachen wie JavaScript, Python und Ruby sind alle einheitlich. Auch hier haben der typeof
Operator in JavaScript und die type
Funktion in Python irreführende Namen. Sie geben die den Operanden zugeordneten Tags zurück, nicht ihre Typen. In ähnlicher Weise dynamic_cast
in C ++ und instanceof
in Java tut nicht tun Typprüfungen.
"Wenn der Quellcode übersetzt wird"
"Wenn Typen überprüft werden"
5 + '3'
ist ein Beispiel für einen Typfehler in stark typisierten Sprachen wie Go und Python, da sie keinen "Typzwang" zulassen -> die Fähigkeit eines Werts, den Typ in bestimmten Kontexten zu ändern, z. B. beim Zusammenführen zweier Typen. Schwach typisierte Sprachen wie JavaScript lösen keinen Tippfehler aus (führt zu '53'
).
Die Definitionen von "Static & Compiled" und "Dynamic & Interpreted" sind ziemlich ähnlich ... aber denken Sie daran, es ist "wenn Typen überprüft werden" vs. "wenn Quellcode übersetzt wird".
Sie erhalten die gleichen Typfehler, unabhängig davon, ob die Sprache kompiliert oder interpretiert wird ! Sie müssen diese Begriffe konzeptionell trennen.
Dynamisch, interpretiert
def silly(a):
if a > 0:
print 'Hi'
else:
print 5 + '3'
silly(2)
Da Python sowohl interpretiert als auch dynamisch typisiert wird, übersetzt und überprüft es nur den Code, für den es ausgeführt wird. Der else
Block wird nie ausgeführt, wird also 5 + '3'
nie angeschaut!
Was ist, wenn es statisch getippt wurde?
Ein Typfehler wird ausgelöst, bevor der Code überhaupt ausgeführt wird. Es führt weiterhin eine Typprüfung vor der Laufzeit durch, obwohl es interpretiert wird.
Was ist, wenn es kompiliert wurde?
Der else
Block würde vor der Laufzeit übersetzt / betrachtet, aber da er dynamisch eingegeben wird, würde er keinen Fehler auslösen! Dynamisch typisierte Sprachen prüfen Typen erst nach der Ausführung, und diese Zeile wird nie ausgeführt.
Statisch, kompiliert
package main
import ("fmt"
)
func silly(a int) {
if (a > 0) {
fmt.Println("Hi")
} else {
fmt.Println("3" + 5)
}
}
func main() {
silly(2)
}
Die Typen werden vor dem Ausführen überprüft (statisch) und der Typfehler wird sofort abgefangen! Die Typen würden noch vor der Laufzeit überprüft, wenn sie interpretiert würden, mit dem gleichen Ergebnis. Wenn es dynamisch wäre, würde es keine Fehler auslösen, obwohl der Code während der Kompilierung betrachtet würde.
Eine kompilierte Sprache hat zur Laufzeit eine bessere Leistung, wenn sie statisch (im Vergleich zu dynamisch) typisiert ist. Die Kenntnis der Typen ermöglicht die Optimierung des Maschinencodes.
Statisch typisierte Sprachen weisen zur Laufzeit eine bessere Leistung auf, da die Typen während der Ausführung nicht dynamisch überprüft werden müssen (dies wird vor der Ausführung überprüft).
In ähnlicher Weise sind kompilierte Sprachen zur Laufzeit schneller, da der Code bereits übersetzt wurde, anstatt ihn im laufenden Betrieb "interpretieren" / übersetzen zu müssen.
Beachten Sie, dass sowohl kompilierte als auch statisch typisierte Sprachen eine Verzögerung haben, bevor sie zur Übersetzung bzw. Typprüfung ausgeführt werden.
Durch statische Typisierung werden Fehler frühzeitig erkannt, anstatt sie während der Ausführung zu finden (besonders nützlich für lange Programme). Es ist "strenger", da es keine Typfehler in Ihrem Programm zulässt und häufig verhindert, dass Variablen Typen ändern, was sich weiter gegen unbeabsichtigte Fehler schützt.
num = 2
num = '3' // ERROR
Dynamisches Tippen ist flexibler, was einige zu schätzen wissen. In der Regel können Variablen den Typ ändern, was zu unerwarteten Fehlern führen kann.
Statisch typisierte Sprachen : Jede Variable und jeder Ausdruck ist bereits zur Kompilierungszeit bekannt.
( int a;
a kann zur Laufzeit nur ganzzahlige Werte annehmen)
Beispiele: C, C ++, Java
Dynamisch typisierte Sprachen : Variablen können zur Laufzeit unterschiedliche Werte erhalten und ihr Typ wird zur Laufzeit definiert.
( var a;
a kann zur Laufzeit beliebige Werte annehmen)
Beispiele: Ruby, Python.
Statisch typisierte Sprachen werden beim Kompilieren auf Typ überprüft, und der Typ kann sich NICHT ändern. (Werden Sie nicht süß mit Typ-Casting-Kommentaren, eine neue Variable / Referenz wird erstellt).
Dynamisch typisierte Sprachen - Typprüfung zur Laufzeit und Typ einer Variablen können zur Laufzeit geändert werden.
Süße und einfache Definitionen, aber passend zum Bedarf: Statisch typisierte Sprachen binden den Typ für den gesamten Bereich an eine Variable (Seg: SCALA). Dynamisch typisierte Sprachen binden den Typ an den tatsächlichen Wert, auf den eine Variable verweist.
Statisch typisierte Sprachen wie C ++, Java und dynamisch typisierte Sprachen wie Python unterscheiden sich nur hinsichtlich der Ausführung des Variablentyps. Statisch typisierte Sprachen haben einen statischen Datentyp für die Variable. Hier wird der Datentyp beim Kompilieren überprüft, sodass das Debuggen viel einfacher ist. Während dynamisch typisierte Sprachen nicht dasselbe tun, wird der Datentyp überprüft, der das Programm ausführt, und damit der Das Debuggen ist etwas schwierig.
Darüber hinaus haben sie einen sehr kleinen Unterschied und können mit stark typisierten und schwach typisierten Sprachen in Verbindung gebracht werden. Eine stark typisierte Sprache erlaubt es Ihnen nicht, einen Typ als einen anderen zu verwenden, z. C und C ++ ... während schwach typisierte Sprachen zB Python erlauben
Statisch typisiert
Die Typen werden vor der Laufzeit überprüft, damit Fehler früher erkannt werden können.
Beispiele = c ++
Dynamisch getippt
Die Typen werden während der Ausführung überprüft.
Beispiele = Python
Statisch typisierte Sprachen (der Compiler löst Methodenaufrufe auf und kompiliert Referenzen):
Dynamisch getippte Sprachen (Entscheidungen im laufenden Programm):
Dynamisch typisierte Sprache hilft dabei, Algorithmuskonzepte schnell zu prototypisieren, ohne darüber nachdenken zu müssen, welche Variablentypen verwendet werden müssen (was in statisch typisierten Sprachen erforderlich ist ).
Statische Typisierung: Die Sprachen wie Java und Scala sind statisch typisiert.
Die Variablen müssen definiert und initialisiert werden, bevor sie in einem Code verwendet werden.
zum Beispiel. int x; x = 10;
System.out.println (x);
Dynamische Typisierung: Perl ist eine dynamisch typisierte Sprache.
Variablen müssen nicht initialisiert werden, bevor sie im Code verwendet werden.
y = 10; Verwenden Sie diese Variable im späteren Teil des Codes
$
), array ( @
) und hash ( %
). Der Typ einer Variablen in Perl ist zur Kompilierungszeit bekannt und bleibt für den Rest der Variablenlebensdauer gleich.