Dynamisch getippte Sprachen werden einheitlich getippt
Beim Vergleich von Typsystemen bietet das dynamische Schreiben keinen Vorteil. Dynamische Typisierung ist ein Sonderfall der statischen Typisierung - es ist eine Sprache mit statischer Typisierung, bei der jede Variable denselben Typ hat. Sie können das Gleiche in Java erreichen (Minuspräzision), indem Sie dafür sorgen, dass jede Variable vom Typ Object
ist und dass "Objekt" -Werte vom Typ sind Map<String, Object>
:
void makeItBark(Object dog) {
Map<String, Object> dogMap = (Map<String, Object>) dog;
Runnable bark = (Runnable) dogMap.get("bark");
bark.run();
}
Selbst ohne Reflektion können Sie den gleichen Effekt in nahezu jeder statisch typisierten Sprache erzielen, abgesehen von der syntaktischen Bequemlichkeit. Sie erhalten keine zusätzliche Ausdruckskraft. im Gegenteil, Sie haben weniger Aussagekraft , weil in einer dynamisch typisierte Sprache, werden Sie verweigern die Möglichkeit , Variablen auf bestimmte Arten zu beschränken.
Eine Entenrinde in einer statisch typisierten Sprache bellen lassen
Darüber hinaus können Sie mit einer guten statischen Sprache Code schreiben, der mit jedem Typ mit einer bark
Operation funktioniert. In Haskell ist dies eine Typklasse:
class Barkable a where
bark :: a -> unit
Dies drückt die Einschränkung aus, dass für einen Typ a
, der als Barkable betrachtet werden soll, eine bark
Funktion vorhanden sein muss , die einen Wert dieses Typs annimmt und nichts zurückgibt.
Sie können dann generische Funktionen in Bezug auf die Barkable
Einschränkung schreiben :
makeItBark :: Barkable a => a -> unit
makeItBark barker = bark (barker)
Dies bedeutet, dass makeItBark
es für jeden Typ geeignet ist Barkable
, der die Anforderungen erfüllt. Dies mag interface
Java oder C # ähneln, hat aber einen großen Vorteil: Typen müssen nicht im Voraus angeben , welchen Typklassen sie entsprechen. Ich kann diese Art sagen Duck
ist Barkable
jederzeit, auch wenn Duck
ein Dritte Typ ich nicht schreiben. Tatsächlich spielt es keine Rolle, dass der Schreiber von Duck
keine bark
Funktion geschrieben hat - ich kann sie nachträglich bereitstellen, wenn ich der Sprache sage, die Folgendes Duck
erfüllt Barkable
:
instance Barkable Duck where
bark d = quack (punch (d))
makeItBark (aDuck)
Dies besagt, dass Duck
s bellen können, und ihre Barkenfunktion wird implementiert, indem die Ente gestanzt wird, bevor sie quakt. Wenn das nicht im Weg ist, können wir makeItBark
Enten suchen.
Standard ML
und OCaml
sind noch flexibler, da Sie dieselbe Typenklasse auf mehr als eine Weise erfüllen können. In diesen Sprachen kann ich sagen, dass ganze Zahlen mit der herkömmlichen Reihenfolge geordnet werden können und sich dann umdrehen und sagen, dass sie auch durch Teilbarkeit geordnet werden können (z. B. 10 > 5
weil 10 durch 5 teilbar ist). In Haskell können Sie eine Typklasse nur einmal instanziieren. (Auf diese Weise weiß Haskell automatisch, dass es in Ordnung ist, bark
eine Ente anzurufen . In SML oder OCaml müssen Sie genau angeben, welche bark
Funktion Sie möchten, da es möglicherweise mehr als eine geben kann.)
Prägnanz
Natürlich gibt es syntaktische Unterschiede. Der von Ihnen vorgestellte Python-Code ist weitaus prägnanter als das von mir geschriebene Java-Äquivalent. In der Praxis ist diese Prägnanz ein wesentlicher Bestandteil der Faszination dynamisch typisierter Sprachen. Aber Typinferenz ermöglicht es Ihnen , Code zu schreiben, in nur so kurz ist statisch typisierten Sprachen, indem Sie entlasten zu müssen explizit die Typen schreiben jede Variable. Eine statisch typisierte Sprache kann auch native Unterstützung für dynamisches Schreiben bieten und die Ausführlichkeit aller Casting- und Kartenmanipulationen (z. B. C # dynamic
) beseitigen .
Richtige, aber falsch geschriebene Programme
Um fair zu sein, schließt statische Typisierung notwendigerweise einige technisch korrekte Programme aus, obwohl die Typprüfung dies nicht überprüfen kann. Beispielsweise:
if this_variable_is_always_true:
return "some string"
else:
return 6
Die meisten statisch typisierten Sprachen würden diese if
Anweisung ablehnen , obwohl die else-Verzweigung niemals auftreten wird. In der Praxis scheint niemand diese Art von Code zu verwenden - alles, was für die Typprüfung zu clever ist, wird wahrscheinlich dazu führen, dass zukünftige Betreuer Ihres Codes Sie und Ihre nächsten Verwandten verfluchen. Beispiel: Jemand hat erfolgreich 4 Open-Source-Python-Projekte in Haskell übersetzt, was bedeutet, dass er nichts getan hat, was eine gute statisch typisierte Sprache nicht kompilieren konnte. Außerdem stellte der Compiler einige typbezogene Fehler fest, die bei den Komponententests nicht festgestellt wurden.
Das stärkste Argument, das ich für dynamisches Tippen gesehen habe, sind Lisps Makros, da Sie damit die Syntax der Sprache beliebig erweitern können. Allerdings typisierten Racket ist eine statisch typisierte Dialekt von Lisp , die Makros hat, so dass es statische Typisierung scheint und Makros schließen sich nicht aus, wenn auch vielleicht härter gleichzeitig zu implementieren.
Äpfel und Orangen
Vergessen Sie nicht, dass die Unterschiede in den Sprachen größer sind als nur das Typensystem. Vor Java 8 war es praktisch unmöglich , irgendeine Art von funktionaler Programmierung in Java durchzuführen. Ein einfaches Lambda würde 4 Zeilen Boilerplate-Code für anonyme Klassen erfordern. Java unterstützt auch keine Sammlungsliterale (z [1, 2, 3]
. B. ). Es kann auch Unterschiede in der Qualität und Verfügbarkeit von Tools (IDEs, Debuggern), Bibliotheken und Community-Support geben. Wenn jemand behauptet, in Python oder Ruby produktiver zu sein als in Java, muss diese Ungleichheit der Funktionen berücksichtigt werden. Es gibt einen Unterschied zwischen dem Vergleichen von Sprachen mit allen enthaltenen Batterien , Sprachkernen und Typensystemen .
makeItBark(collections.namedtuple("Dog", "bark")(lambda x: "woof woof"))
. Dieses Argument ist nicht einmal eine Klasse , es ist ein anonymes Tupel mit dem Namen. Duck Typing ("wenn es wie ein ... quakt") ermöglicht es Ihnen, Ad-hoc-Schnittstellen mit im Wesentlichen null Einschränkungen und ohne syntaktischen Aufwand zu erstellen. Sie können dies in einer Sprache wie Java tun, aber Sie haben am Ende viel chaotisches Nachdenken. Wenn für eine Funktion in Java eine ArrayList erforderlich ist und Sie ihr einen anderen Auflistungstyp zuweisen möchten, sind Sie SOL. In Python kann das nicht einmal hochkommen.