Ich habe eine verwandte Frage gelesen. Gibt es Entwurfsmuster, die in dynamischen Sprachen wie Python nicht erforderlich sind? und erinnerte mich an dieses Zitat auf Wikiquote.org
Das Wunderbare an dynamischer Eingabe ist, dass Sie damit alles ausdrücken können, was berechenbar ist. Typsysteme sind normalerweise nicht bestimmbar und beschränken Sie auf eine Teilmenge. Leute, die statische Systeme bevorzugen, sagen: „Es ist in Ordnung, es ist gut genug. Alle interessanten Programme, die Sie schreiben möchten, funktionieren als Typen. “ Aber das ist lächerlich - wenn Sie ein Typensystem haben, wissen Sie nicht einmal, welche interessanten Programme es gibt.
--- Software Engineering Radio Folge 140: Newspeak und Pluggable Types mit Gilad Bracha
Ich frage mich, ob es nützliche Entwurfsmuster oder -strategien gibt, die mit der Formulierung des Zitats "nicht als Typen arbeiten"?
Antworten:
Erstklassige Typen
Dynamische Typisierung bedeutet, dass Sie erstklassige Typen haben: Sie können Typen zur Laufzeit überprüfen, erstellen und speichern, einschließlich der sprachspezifischen Typen. Dies bedeutet auch, dass Werte eingegeben werden und keine Variablen .
Statisch typisierte Sprache kann Code erzeugen, der ebenfalls auf dynamischen Typen beruht, wie z. B. Methodenversand, Typklassen usw., jedoch auf eine Weise, die für die Laufzeit im Allgemeinen unsichtbar ist. Bestenfalls geben sie Ihnen die Möglichkeit, eine Selbstbeobachtung durchzuführen. Alternativ können Sie Typen als Werte simulieren, haben aber dann ein dynamisches Ad-hoc-Typensystem.
Dynamische Typsysteme haben jedoch selten nur erstklassige Typen. Sie können erstklassige Symbole, erstklassige Pakete, erstklassige ... alles haben. Dies steht im Gegensatz zu der strikten Trennung zwischen der Compilersprache und der Laufzeitsprache in statisch typisierten Sprachen. Was der Compiler oder Interpreter kann, kann auch die Laufzeit tun.
Lassen Sie uns nun zustimmen, dass die Typinferenz eine gute Sache ist und dass ich meinen Code gerne überprüfen lasse, bevor ich ihn ausführe. Ich mag es aber auch, zur Laufzeit Code erzeugen und kompilieren zu können. Und ich liebe es, Dinge zur Kompilierungszeit vorauszurechnen. In einer dynamisch getippten Sprache erfolgt dies mit derselben Sprache. In OCaml haben Sie das Modul- / Funktortypsystem, das sich vom Haupttypsystem unterscheidet, das sich von der Präprozessorsprache unterscheidet. In C ++ haben Sie die Vorlagensprache, die nichts mit der Hauptsprache zu tun hat, die während der Ausführung im Allgemeinen keine Typenkenntnisse aufweist. Und das ist in dieser Sprache in Ordnung , weil sie nicht mehr bieten wollen.
Letztendlich ändert das nicht wirklich, welche Art von Software Sie entwickeln können, aber die Ausdruckskraft ändert, wie Sie sie entwickeln und ob es schwierig ist oder nicht.
Muster
Muster, die auf dynamischen Typen basieren, sind Muster, die dynamische Umgebungen umfassen: offene Klassen, Dispatching, In-Memory-Datenbanken von Objekten, Serialisierung usw. Einfache Dinge wie generische Container funktionieren, weil ein Vektor zur Laufzeit nicht den Typ der darin enthaltenen Objekte vergisst (keine Notwendigkeit für parametrische Typen).
Ich habe versucht, die vielen Arten der Codeauswertung in Common Lisp sowie Beispiele für mögliche statische Analysen einzuführen (dies ist SBCL). Das Sandbox-Beispiel kompiliert eine kleine Teilmenge des Lisp-Codes, der aus einer separaten Datei abgerufen wird. Um einigermaßen sicher zu sein, ändere ich die Lesetabelle, lasse nur eine Teilmenge der Standardsymbole zu und bringe Dinge mit einer Zeitüberschreitung in einen Zeilenumbruch.
Nichts oben ist "unmöglich", mit anderen Sprachen zu tun. Der Plug-in-Ansatz in Blender, in Musiksoftware oder IDEs für statisch kompilierte Sprachen, die eine schnelle Neukompilierung durchführen usw. Anstelle von externen Tools bevorzugen dynamische Sprachen Tools, die bereits vorhandene Informationen verwenden. Alle bekannten Anrufer von FOO? alle Unterklassen von BAR? alle Methoden, die von Klasse ZOT spezialisiert sind? Dies sind internalisierte Daten. Typen sind nur ein weiterer Aspekt.
(siehe auch: CFFI )
quelle
Kurze Antwort: Nein, weil Turing Äquivalenz.
Lange Antwort: Dieser Typ ist ein Troll. Während es stimmt, dass Typsysteme "Sie auf eine Teilmenge beschränken", sind die Dinge außerhalb dieser Teilmenge per Definition Dinge, die nicht funktionieren.
Alles, was Sie in einer Turing-vollständigen Programmiersprache tun können (eine Sprache, die für die allgemeine Programmierung entwickelt wurde, plus viele, die nicht vorhanden sind). Es ist ein ziemlich niedriger Balken, der zu übersehen ist, und es gibt mehrere Beispiele dafür, wie ein System zu Turing wird. komplettieren Sie unbeabsichtigt), die Sie in jeder anderen Programmiersprache von Turing-complete ausführen können. Dies wird "Turing-Äquivalenz" genannt und bedeutet nur genau das, was es sagt. Wichtig ist, dass Sie das andere nicht genauso einfach in der anderen Sprache tun können - einige würden argumentieren, dass dies der springende Punkt bei der Erstellung einer neuen Programmiersprache ist: Ihnen eine bessere Möglichkeit zu geben, bestimmte Dinge zu tun Dinge, an denen existierende Sprachen scheißen.
Ein dynamisches Typsystem kann beispielsweise über ein statisches OO-Typsystem emuliert werden, indem einfach alle Variablen, Parameter und Rückgabewerte als Basistyp deklariert werden
Object
und dann mithilfe von Reflection auf die spezifischen Daten in diesem System zugegriffen wird Sie sehen, dass Sie in einer dynamischen Sprache buchstäblich nichts tun können, was Sie in einer statischen Sprache nicht tun können. Aber das wäre natürlich ein großes Durcheinander.Der Typ aus dem Zitat ist richtig, dass statische Typen Ihre Möglichkeiten einschränken, aber das ist ein wichtiges Merkmal, kein Problem. Die Linien auf der Straße beschränken, was Sie in Ihrem Auto tun können, aber finden Sie sie einschränkend oder hilfreich? (Ich weiß, dass ich nicht auf einer viel befahrenen, komplexen Straße fahren möchte, auf der die Autos nicht in die entgegengesetzte Richtung fahren müssen, um auf ihrer Seite zu bleiben und nicht dahin zu kommen, wo ich fahre!) Indem Sie Regeln aufstellen, die klar definieren, was ist Sie werden als ungültiges Verhalten eingestuft und stellen sicher, dass dies nicht passiert. Dadurch verringern Sie die Wahrscheinlichkeit eines bösen Absturzes erheblich.
Außerdem charakterisiert er die andere Seite falsch. Es ist nicht so, dass "alle interessanten Programme, die Sie schreiben möchten, als Typen funktionieren", sondern dass "alle interessanten Programme, die Sie schreiben möchten, Typen erfordern ". Sobald Sie ein bestimmtes Maß an Komplexität überschritten haben, wird es aus zwei Gründen sehr schwierig, die Codebasis ohne ein Typsystem aufrechtzuerhalten, das Sie auf dem Laufenden hält.
Erstens, weil Code ohne Typanmerkungen schwer zu lesen ist. Betrachten Sie das folgende Python:
Wie sehen die Daten aus, die das System am anderen Ende der Verbindung empfängt? Und wenn es etwas empfängt, das völlig falsch aussieht, wie finden Sie heraus, was los ist?
Auf die Struktur von kommt es an
value.someProperty
. Aber wie sieht es aus? Gute Frage! Was ruft ansendData()
? Was vergeht? Wie sieht diese Variable aus? Wo ist es hergekommen? Wenn es nicht lokal ist, müssen Sie die gesamte Historie nachverfolgen,value
um herauszufinden, was los ist. Möglicherweise übergeben Sie etwas anderes, das ebenfalls einesomeProperty
Eigenschaft hat, aber nicht das tut, was Sie denken, dass dies der Fall ist?Schauen wir uns das jetzt mit Typanmerkungen an, wie Sie vielleicht in der Boo-Sprache sehen, die eine sehr ähnliche Syntax verwendet, aber statisch geschrieben ist:
Wenn etwas schief geht, ist Ihre Debug-Aufgabe plötzlich um eine Größenordnung einfacher geworden: Sehen Sie sich die Definition von
MyDataType
! Außerdem wird die Wahrscheinlichkeit, dass Sie sich schlecht verhalten, weil Sie einen inkompatiblen Typ übergeben haben, der auch eine Eigenschaft mit demselben Namen hat, plötzlich auf Null gesetzt, weil das Typensystem Sie nicht dazu veranlasst, diesen Fehler zu machen.Der zweite Grund baut auf dem ersten auf: In einem großen und komplexen Projekt haben Sie höchstwahrscheinlich mehrere Mitwirkende. (Und wenn nicht, bauen Sie es über einen langen Zeitraum selbst, was im Wesentlichen dasselbe ist. Versuchen Sie, Code zu lesen, den Sie vor 3 Jahren geschrieben haben, wenn Sie mir nicht glauben!) Dies bedeutet, dass Sie nicht wissen, was war Ich gehe den Kopf der Person durch, die fast jeden Teil des Codes zu dem Zeitpunkt geschrieben hat, als sie ihn geschrieben hat, weil Sie nicht da waren, oder ich erinnere mich nicht, ob es vor langer Zeit Ihr eigener Code war. Wenn Sie Typdeklarationen haben, können Sie die Absicht des Codes besser verstehen!
Leute wie der Typ im Zitat bezeichnen die Vorteile des statischen Tippens häufig als "Hilfe für den Compiler" oder "Alles über Effizienz" in einer Welt, in der nahezu unbegrenzte Hardwareressourcen dies mit jedem Jahr weniger relevant machen. Aber wie ich gezeigt habe, gibt es diese Vorteile sicherlich, aber der Hauptvorteil liegt in den menschlichen Faktoren, insbesondere der Lesbarkeit und Wartbarkeit des Codes. (Die gesteigerte Effizienz ist aber sicherlich ein schöner Bonus!)
quelle
Ich werde den 'Muster'-Teil auslassen, weil ich denke, dass er sich in der Definition dessen, was ein Muster ist oder nicht, widerspiegelt und ich das Interesse an dieser Debatte schon lange verloren habe. Was ich sagen werde, ist, dass es Dinge gibt, die Sie in einigen Sprachen tun können, die Sie in anderen nicht tun können. Lassen Sie mich klar sein, ich sage nicht , dass es Probleme gibt, die Sie in einer Sprache lösen können, die Sie in einer anderen nicht lösen können. Mason hat bereits auf die Vollständigkeit hingewiesen.
Ich habe zum Beispiel eine Klasse in Python geschrieben, die ein XML-DOM-Element umschließt und es zu einem erstklassigen Objekt macht. Das heißt, Sie können den Code schreiben:
und Sie haben den Inhalt dieses Pfads in einem analysierten XML-Objekt. Art ordentlich und ordentlich, IMO. Und wenn es keinen Hauptknoten gibt, gibt er nur Dummy-Objekte zurück, die nichts als Dummy-Objekte enthalten (Schildkröten bis zum Ende). In Java gibt es keine echte Möglichkeit, dies zu tun. Sie müssten im Voraus eine Klasse kompiliert haben, die auf einigen Kenntnissen der XML-Struktur basiert. Abgesehen davon, dass dies eine gute Idee ist, ändert dies die Art und Weise, wie Sie Probleme in einer dynamischen Sprache lösen. Ich sage nicht, dass es sich auf eine Weise ändert, die notwendigerweise immer besser ist. Dynamische Ansätze sind mit gewissen Kosten verbunden, und die Antwort von Mason gibt einen guten Überblick. Ob sie eine gute Wahl sind, hängt von vielen Faktoren ab.
Nebenbei bemerkt, Sie können dies in Java tun, da Sie einen Python-Interpreter in Java erstellen können . Die Tatsache, dass das Lösen eines bestimmten Problems in einer bestimmten Sprache bedeuten kann, einen Dolmetscher oder etwas Ähnliches zu bauen, wird oft übersehen, wenn über die Vollständigkeit von Turing gesprochen wird.
quelle
IDynamicMetaObjectProvider
, und in Boo ist es denkbar einfach. ( Hier ist eine Implementierung in weniger als 100 Zeilen, die als Teil des Standardquellbaums von GitHub enthalten ist, weil es so einfach ist!)"IDynamicMetaObjectProvider"
? Steht das in Zusammenhang mit demdynamic
Schlüsselwort von C # ? ... was greift eigentlich nur beim dynamischen Tippen in C # an? Ich bin mir nicht sicher, ob Ihr Argument zutrifft, wenn ich recht habe.dynamic
das in C # erreicht wird. "Reflection and Dictionary Lookups" finden zur Laufzeit statt, nicht zur Kompilierungszeit. Ich bin mir wirklich nicht sicher, wie Sie einen Fall erstellen können, bei dem der Sprache keine dynamische Typisierung hinzugefügt wird. Mein Punkt ist, dass Jimmys letzter Absatz das behandelt.Das Zitat ist richtig, aber auch sehr unaufrichtig. Lassen Sie es uns zusammenfassen, um zu sehen, warum:
Nicht ganz. Mit einer Sprache mit dynamischer Eingabe können Sie alles ausdrücken, solange Turing vollständig ist , was die meisten sind. Das Typensystem selbst lässt Sie nicht alles ausdrücken. Lassen Sie uns ihm den Vorteil des Zweifels hier geben.
Dies ist wahr, aber beachten Sie, dass wir jetzt genau darüber sprechen, was das Typensystem zulässt und nicht, was die Sprache , die ein Typensystem verwendet, zulässt. Während es möglich ist, ein Typensystem zu verwenden, um Sachen zur Kompilierungszeit zu berechnen, ist dies im Allgemeinen nicht vollständig (da das Typensystem im Allgemeinen entscheidbar ist), aber fast jede statisch typisierte Sprache ist auch in ihrer Laufzeit vollständig (abhängig typisierte Sprachen) nicht, aber ich glaube nicht, dass wir hier über sie sprechen).
Das Problem ist, dass dynamisch typisierte Sprachen einen statischen Typ haben. Manchmal ist alles eine Zeichenfolge, und häufiger gibt es eine getaggte Vereinigung, bei der alles entweder eine Tasche mit Eigenschaften oder ein Wert wie ein int oder ein double ist. Das Problem ist, dass dies auch mit statischen Sprachen möglich ist. In der Vergangenheit war dies etwas umständlicher. Moderne statisch typisierte Sprachen machen dies jedoch so einfach wie die Verwendung einer dynamisch typisierten Sprache. Wie kann es also Unterschiede geben? was kann der programmierer als interessantes programm sehen? Statische Sprachen haben genau die gleichen Gewerkschaften wie andere Typen.
Um die Frage im Titel zu beantworten: Nein, es gibt keine Entwurfsmuster, die nicht in einer statisch typisierten Sprache implementiert werden können, da Sie immer genügend dynamische Systeme implementieren können, um sie abzurufen. Es kann Muster geben, die Sie kostenlos in einer dynamischen Sprache erhalten. Dies könnte es wert sein, die Nachteile dieser Sprachen für YMMV in Kauf zu nehmen .
quelle
Es gibt sicherlich Dinge, die Sie nur in dynamisch getippten Sprachen tun können. Aber sie wären nicht unbedingt gutes Design.
Sie können derselben Variablen zuerst eine Ganzzahl 5, dann eine Zeichenfolge
'five'
oder einCat
Objekt zuweisen . Aber Sie machen es einem Leser Ihres Codes nur schwerer, herauszufinden, was los ist und wozu jede Variable dient.Sie können einer Ruby-Klasse in der Bibliothek eine neue Methode hinzufügen und auf ihre privaten Felder zugreifen. Es mag Fälle geben, in denen ein solcher Hack nützlich sein kann, dies wäre jedoch eine Verletzung der Kapselung. (Es macht mir nichts aus, Methoden hinzuzufügen, die sich nur auf die öffentliche Schnittstelle stützen, aber das ist nichts, was statisch typisierte C # -Erweiterungsmethoden nicht können.)
Sie können einem Objekt der Klasse eines anderen ein neues Feld hinzufügen, um damit zusätzliche Daten weiterzuleiten. Es ist jedoch besser, einfach eine neue Struktur zu erstellen oder den ursprünglichen Typ zu erweitern.
Je organisierter der Code bleiben soll, desto weniger sollten Sie in der Lage sein, Typdefinitionen dynamisch zu ändern oder Werte verschiedener Typen derselben Variablen zuzuweisen. Aber Ihr Code unterscheidet sich nicht von dem, was Sie in einer statisch typisierten Sprache erreichen könnten.
Was dynamische Sprachen können, ist syntaktischer Zucker. Wenn Sie beispielsweise ein deserialisiertes JSON-Objekt lesen, verweisen Sie möglicherweise auf einen verschachtelten Wert, der einfach so
obj.data.article[0].content
viel aussagekräftiger ist als beispielsweiseobj.getJSONObject("data").getJSONArray("article").getJSONObject(0).getString("content")
.Insbesondere Ruby-Entwickler könnten sich ausführlich über die Magie unterhalten, die durch die Implementierung erzielt werden kann. Diese
method_missing
Methode ermöglicht es Ihnen, versuchte Aufrufe nicht deklarierter Methoden zu verarbeiten. ActiveRecord ORM verwendet es beispielsweise, damit Sie einen Anruf tätigen können,User.find_by_email('[email protected]')
ohne jemals einefind_by_email
Methode zu deklarieren . Natürlich ist es nichts, was man nicht wieUserRepository.FindBy("email", "[email protected]")
in einer statisch getippten Sprache erreichen kann, aber man kann es nicht leugnen, dass es ordentlich ist.quelle
Das Dynamic Proxy-Muster ist eine Verknüpfung zum Implementieren von Proxy-Objekten, ohne dass eine Klasse pro Typ zum Proxy benötigt wird.
Mit diesem
Proxy(someObject)
Befehl wird ein neues Objekt erstellt, das sich genauso verhält wiesomeObject
. Natürlich möchten Sie auch zusätzliche Funktionen hinzufügen, aber dies ist eine nützliche Basis, um von hier aus zu beginnen. In einer vollständigen statischen Sprache müssen Sie entweder eine Proxy-Klasse pro Typ schreiben, für den Sie einen Proxy erstellen möchten, oder die dynamische Codegenerierung verwenden (die zugegebenermaßen in der Standardbibliothek vieler statischer Sprachen enthalten ist, vor allem, weil ihre Designer dies kennen die Probleme, die dazu nicht in der Lage sind).Ein weiterer Anwendungsfall für dynamische Sprachen ist das sogenannte "Monkey Patching". In vielerlei Hinsicht ist dies ein anti-Muster eher als ein Muster, aber es kann sorgfältig wenn man sich in nützlicher Weise verwendet werden. Und obwohl es keinen theoretischen Grund dafür gibt, dass Affen-Patches nicht in einer statischen Sprache implementiert werden können, habe ich noch nie eine gesehen, die diese tatsächlich enthält.
quelle
Ja , es gibt viele Muster und Techniken, die nur in einer dynamisch getippten Sprache möglich sind.
Monkey Patching ist eine Technik, bei der Objekte oder Klassen zur Laufzeit um Eigenschaften oder Methoden erweitert werden. Diese Technik ist in einer statisch typisierten Sprache nicht möglich, da dies bedeutet, dass Typen und Operationen zur Kompilierungszeit nicht überprüft werden können. Oder anders ausgedrückt: Wenn eine Sprache Affen-Patches unterstützt, ist sie per Definition eine dynamische Sprache.
Es kann nachgewiesen werden, dass eine Sprache, die Affenpatching (oder ähnliche Techniken zum Ändern von Typen zur Laufzeit) unterstützt, nicht statisch typgeprüft werden kann. Es handelt sich also nicht nur um eine Einschränkung der derzeit vorhandenen Sprachen, sondern auch um eine grundlegende Einschränkung der statischen Typisierung.
Das Zitat ist also definitiv richtig - in einer dynamischen Sprache sind mehr Dinge möglich als in einer statisch typisierten Sprache. Andererseits sind bestimmte Arten der Analyse nur in einer statisch typisierten Sprache möglich. Beispielsweise wissen Sie immer, welche Operationen für einen bestimmten Typ zulässig sind, wodurch Sie ungültige Operationen beim Kompilierungstyp erkennen können. In einer dynamischen Sprache ist eine solche Überprüfung nicht möglich, wenn Operationen zur Laufzeit hinzugefügt oder entfernt werden können.
Aus diesem Grund gibt es im Konflikt zwischen statischen und dynamischen Sprachen kein offensichtliches "Beste". Statische Sprachen geben zur Laufzeit eine gewisse Leistung ab, während sie zur Kompilierungszeit eine andere Leistung zur Verfügung stellen. Sie sind der Ansicht, dass dies die Anzahl der Fehler verringert und die Entwicklung erleichtert. Einige glauben, dass sich der Kompromiss lohnt, andere nicht.
Andere Antworten haben argumentiert, dass Turing-Äquivalenz bedeutet, dass alles, was in einer Sprache möglich ist, in allen Sprachen möglich ist. Dies folgt aber nicht. Um so etwas wie das Patchen von Affen in einer statischen Sprache zu unterstützen, müssen Sie grundsätzlich eine dynamische Untersprache in der statischen Sprache implementieren. Dies ist natürlich möglich, aber ich würde behaupten, dass Sie dann in einer eingebetteten dynamischen Sprache programmieren, da Sie auch die statische Typprüfung verlieren, die in der Hostsprache vorhanden ist.
C # unterstützt seit Version 4 dynamisch typisierte Objekte. Die Sprachdesigner sehen eindeutig einen Vorteil darin, dass beide Arten der Eingabe verfügbar sind. Es zeigt aber auch, dass Sie Ihren Kuchen nicht haben und auch nicht essen können: Wenn Sie dynamische Objekte in C # verwenden, erhalten Sie die Möglichkeit, so etwas wie Affen-Patches auszuführen, verlieren jedoch auch die statische Typüberprüfung für die Interaktion mit diesen Objekten.
quelle
Ja und nein.
Es gibt Situationen, in denen der Programmierer den Typ einer Variablen genauer kennt als ein Compiler. Der Compiler kann wissen, dass etwas ein Objekt ist, aber der Programmierer wird (aufgrund der Invarianten des Programms) wissen, dass es sich tatsächlich um einen String handelt.
Lassen Sie mich einige Beispiele dafür zeigen:
Ich weiß, dass
someMap.get(T.class)
ein zurückkehren wirdFunction<T, String>
, weil ich so eine Karte erstellt habe. Aber Java ist nur sicher, dass ich eine Funktion habe.Ein anderes Beispiel:
Ich weiß, dass data.properties.rowCount eine gültige Referenz und eine Ganzzahl ist, da ich die Daten anhand eines Schemas überprüft habe. Wenn dieses Feld fehlen würde, wäre eine Ausnahme ausgelöst worden. Ein Compiler würde jedoch nur wissen, dass er entweder eine Ausnahme auslöst oder eine Art generischen JSONValue zurückgibt.
Ein anderes Beispiel:
Die "II6s" definieren die Art und Weise, wie Daten drei Variablen codieren. Da ich das Format angegeben habe, weiß ich, welche Typen zurückgegeben werden. Ein Compiler würde nur wissen, dass er ein Tupel zurückgibt.
Das verbindende Thema all dieser Beispiele ist, dass der Programmierer den Typ kennt, aber ein Java-Level-Typ-System kann dies nicht widerspiegeln. Der Compiler kennt die Typen nicht und daher kann ich sie in einer statisch typisierten Sprache nicht aufrufen, wohingegen dies in einer dynamisch typisierten Sprache der Fall ist.
So lautet das ursprüngliche Zitat:
Bei Verwendung der dynamischen Typisierung kann ich den am besten abgeleiteten Typ verwenden, den ich kenne, und nicht nur den am besten abgeleiteten Typ, den das Typensystem meiner Sprache kennt. In allen oben genannten Fällen habe ich Code, der semantisch korrekt ist, aber von einem statischen Typisierungssystem abgelehnt wird.
Um jedoch zu Ihrer Frage zurückzukehren:
Jedes der obigen Beispiele und in der Tat jedes Beispiel für dynamische Typisierung kann beim statischen Typisieren durch Hinzufügen geeigneter Casts gültig gemacht werden. Wenn Sie einen Typ kennen, den Ihr Compiler nicht kennt, teilen Sie dies dem Compiler einfach mit, indem Sie den Wert eingeben. Auf einer bestimmten Ebene erhalten Sie also keine zusätzlichen Muster, wenn Sie dynamisches Tippen verwenden. Möglicherweise müssen Sie nur mehr Casts erstellen, um mit statisch eingegebenem Code arbeiten zu können.
Der Vorteil der dynamischen Typisierung besteht darin, dass Sie diese Muster einfach verwenden können, ohne sich darüber zu ärgern, dass es schwierig ist, Ihr Typensystem von ihrer Gültigkeit zu überzeugen. Die verfügbaren Muster werden dadurch nicht geändert, sondern möglicherweise einfacher implementiert, da Sie nicht herausfinden müssen, wie Ihr Typensystem das Muster erkennt oder Casts hinzufügt, um das Typensystem zu unterwandern.
quelle
data = parseJSON<SomeSchema>(someJson); print(data.properties.rowCount);
und wenn man keine Klasse zum Deserialisieren hat, kann man auf diese zurückgreifen,data = parseJSON(someJson); print(data["properties.rowCount"]);
die immer noch typisiert ist und die gleiche Absicht ausdrückt.data.properties
es sich um ein Objekt handelte und dassdata.properties.rowCount
es sich um eine Ganzzahl handelte, und dass ich einfach Code schreiben konnte, der sie verwendete. Ihr Vorschlagdata["properties.rowCount"]
sieht nicht dasselbe vor.Hier sind einige Beispiele aus Objective-C (dynamisch typisiert), die in C ++ (statisch typisiert) nicht möglich sind:
Objekte mehrerer verschiedener Klassen in denselben Container stellen.
Dies erfordert natürlich eine Laufzeitüberprüfung, um anschließend den Inhalt des Containers zu interpretieren, und die meisten Freunde der statischen Typisierung werden einwenden, dass Sie dies gar nicht erst tun sollten. Aber ich habe festgestellt, dass dies jenseits der religiösen Debatten nützlich sein kann.
Erweitern einer Klasse ohne Unterklassen
In Objective-C können Sie neue Elementfunktionen für vorhandene Klassen definieren, einschließlich sprachdefinierter Funktionen wie z
NSString
. Zum Beispiel können Sie eine Methode hinzufügenstripPrefixIfPresent:
, damit Sie sagen können[@"foo/bar/baz" stripPrefixIfPresent:@"foo/"]
(beachten Sie die Verwendung derNSSring
Literale@""
).Verwendung von objektorientierten Rückrufen.
In statisch typisierten Sprachen wie Java und C ++ müssen Sie erhebliche Anstrengungen unternehmen, damit eine Bibliothek ein beliebiges Mitglied eines vom Benutzer bereitgestellten Objekts aufrufen kann. In Java ist die Problemumgehung das Interface / Adapter-Paar plus eine anonyme Klasse, in C ++ ist die Problemumgehung normalerweise vorlagenbasiert, was impliziert, dass Bibliothekscode für Benutzercode verfügbar gemacht werden muss. In Objective-C übergeben Sie einfach die Objektreferenz sowie den Selektor für die Methode an die Bibliothek, und die Bibliothek kann den Rückruf einfach und direkt aufrufen.
quelle
void*
alleine ist kein dynamisches Tippen, es ist ein Mangel an Tippen. Aber ja, dynamic_cast, virtuelle Tabellen usw. machen C ++ nicht rein statisch typisiert. Ist das schlecht?void*
bestimmten Objekttyp zu werfen . Ersteres führt zu einem Laufzeitfehler, wenn Sie Fehler gemacht haben. Letzteres führt zu undefiniertem Verhalten.