it-swarm-eu.dev

Was ist der vermeintliche Produktivitätsgewinn beim dynamischen Tippen?

Ich habe oft die Behauptung gehört, dass dynamisch typisierte Sprachen produktiver sind als statisch typisierte Sprachen. Was sind die Gründe für diese Behauptung? Ist es nicht nur ein Werkzeug mit modernen Konzepten wie Konvention über Konfiguration, Verwendung funktionaler Programmierung, fortgeschrittenen Programmiermodellen und Verwendung konsistenter Abstraktionen, die alle auch in statisch typisierten Sprachen verwendet werden können? Zugegeben, es gibt weniger Unordnung, da die (zum Beispiel in Java) häufig redundanten Typdeklarationen nicht benötigt werden. Sie können jedoch auch die meisten Typdeklarationen in statisch typisierten Sprachen, die Typinferenz verwenden, weglassen, ohne die anderen Vorteile der statischen Typisierung zu verlieren. Und all dies ist auch für moderne statisch typisierte Sprachen wie Scala) verfügbar.

Also: Was gibt es für die Produktivität beim dynamischen Schreiben zu sagen, das wirklich ein Vorteil des Typmodells selbst ist?

Klarstellung: Ich interessiere mich mehr für große/mittlere Projekte als für schnelle Hacks. :-)

86

Ich denke eigentlich, dass es ein ziemlich enger Anruf ist. Sowohl die dynamische als auch die statische Eingabe haben ihre Vorteile.

Gründe für eine produktivere dynamische Eingabe:

  • Es ist prägnanter - Eine Menge überflüssiger Code kann entfernt werden, wenn alles dynamisch typisiert wird - Typdeklarationen, Typisierungslogik usw. Alle anderen Dinge sind gleich, kürzerer Code ist geringfügig schneller zu schreiben, aber was noch wichtiger ist, er kann schneller gelesen und gewartet werden (da Sie nicht viele Seiten Code durchblättern müssen, um den Überblick zu behalten).
  • Leichter zu "hacken" Techniken wie Enten-Typisierung und Affen-Patching können sehr schnell zu Ergebnissen führen (obwohl sie Sie später verwirren könnten ...)
  • Interaktiver - Dynamische Typisierung eignet sich wahrscheinlich besser für interaktive, REPL-ähnliche Programmierung für Rapid Prototyping, Echtzeit-Debugging laufender Programminstanzen oder sogar Live-Codierung .
  • Testfälle können die Laufzeitfehler abfangen - vorausgesetzt, Sie verwenden TDD oder haben zumindest eine gute Testsuite, sollte dies alle Tippprobleme in aufheben dein Code.
  • Besserer Polymorphismus - Dynamische Sprachen fördern möglicherweise eher die Erstellung polymorpher Funktionen und Abstraktionen, was die Produktivität und die Wiederverwendung von Code steigern kann. Clojure zum Beispiel nutzt den dynamischen Polymorphismus in seinen vielen Abstraktionen .
  • Prototypen - prototypbasiert Daten-/Objektmodelle sind meiner Ansicht nach leistungsfähiger und flexibler als statisch typisierte Vererbungserbschaften. Dynamische Sprachen erlauben oder fördern eher einen prototypbasierten Ansatz, wobei Javascript ein gutes Beispiel ist.

Gründe für eine produktivere statische Eingabe:

  • Besseres Design - Wenn Sie gezwungen sind, über die Arten von Werten in Ihrer Software nachzudenken, können Sie zu saubereren, logischeren Lösungen gelangen. (Ich sage kann - es ist immer noch möglich, wirklich schlechten Code zu entwerfen ...)
  • Bessere Überprüfung der Kompilierungszeit - Durch statische Typisierung können beim Kompilieren mehr Fehler abgefangen werden. Dies ist ein großer Vorteil und wohl das Beste an statisch typisierten Sprachen insgesamt.
  • Automatische Vervollständigung - Die statische Eingabe kann dem IDE auch weitere Informationen geben, damit Code oder Dokumentation automatisch vervollständigt werden Suche ist effektiver.
  • Entmutigt Hacks - Sie müssen die Typendisziplin in Ihrem Code beibehalten, was wahrscheinlich ein Vorteil für die langfristige Wartbarkeit ist.
  • Typinferenz - In einigen Sprachen (z. B. Scala) können Sie dadurch viele der prägnanten Vorteile dynamischer Sprachen erhalten, die die Typendisziplin beibehalten.

Im Durchschnitt komme ich (nach langjähriger Erfahrung auf beiden Seiten des Zauns) zu dem Schluss, dass dynamisches Tippen kurzfristig produktiver sein kann, aber letztendlich schwierig zu warten ist, wenn Sie nicht über sehr gute Testsuiten und Testdisziplin verfügen.

Andererseits bevorzuge ich insgesamt statisch typisierte Ansätze, da ich denke, dass die Korrektheitsvorteile und die Werkzeugunterstützung Ihnen langfristig eine bessere Produktivität ermöglichen.

100
mikera

Mit dynamischen Sprachen können Sie beschissenen Code schneller schreiben als mit einer getippten Sprache.

Sobald Sie schnell Ihren riesigen Haufen dynamischer Dinge erstellt haben, können Sie sicher zu einem anderen Projekt wechseln, ohne sich um die langfristige Wartung kümmern zu müssen.

Das ist Produktivitätsgewinn :)

Ich mache Witze, aber nachdem ich an einem Projekt mit 'dynamischer Sprache' beteiligt war, hatte ich Angst vor der Menge unnötiger Tests, Dokumentationen und Konventionen, mit denen Sie sich befassen müssen, wenn Sie ein funktionierendes Produkt haben möchten.
Und mit der Freude an vielen Laufzeitfehlern, die beim Kompilieren hätten auftreten können.
Oh, ich habe auch vergessen, über all die Hacks und Voodoos zu schimpfen, die Sie durch Meta-Programmierung in Ihren Code einführen können!

Der Produktivitätsgewinn könnte also ein Mythos für ein mittelgroßes/großes Projekt während seiner gesamten Lebensdauer sein.

56
Guillaume

Auch für dieses Problem gibt es eine theoretische Sichtweise: Ein statisches Typsystem ist im Wesentlichen ein spezialisierter Theorembeweiser, der das Programm nur akzeptiert, wenn es die Typkorrektheit beweisen kann. Alle statischen Typsysteme lehnen einige gültige Programme ab, da kein entscheidbares statisches Typsystem leistungsfähig genug ist, um alle möglichen typkorrekten Programme zu beweisen.

Man könnte argumentieren, dass diese Programme, die von einem statischen Typechecker nicht bewiesen werden können, Hacks und/oder ein schlechter Stil sind. Wenn Sie jedoch bereits ein gültiges Programm haben und der Typechecker es nicht akzeptiert, beeinträchtigt dies auf kurze Sicht sicherlich Ihre Produktivität.

Einige Fälle, in denen Sie möglicherweise feststellen, dass die Typprüfung im Weg steht, sind generische Container und Co-/Contravarianz bei Argumenten und Rückgabetypen.

16
Patrick

Ein Vorteil, den ich bei den meisten dynamischen Sprachen festgestellt habe, ist, dass sie das Schreiben von allgemeinerem Code erleichtern. Es ist viel einfacher, auf einer höheren Abstraktionsebene zu schreiben, wenn Sie nicht gegen das Typensystem kämpfen müssen, um dies zu tun.

Sie müssen nicht so viel darüber nachdenken - das Schreiben von Code, der mit any object in Java etwas Untriviales tut) ist schwierig und erfordert wahrscheinlich eine Reflexion, die im Grunde genommen dynamisch ist Mit etwas wie JavaScript ist das Schreiben einer Funktion, die für alle Objekte etwas Interessantes bewirkt, eine Selbstverständlichkeit. Ein perfektes Beispiel wäre eine Funktion, die ich kürzlich geschrieben habe und die ein Objekt nimmt und alle seine Methoden durch solche ersetzt, die dasselbe tun, aber auch Ich habe keine Ahnung, wie ich so etwas in Java angehen soll. Ich bin mir jedoch nicht sicher, wie viel davon auf die Typsysteme und wie viel auf andere Sprachunterschiede zurückzuführen ist.

Ich habe jedoch kürzlich begonnen, Haskell zu verwenden. Mit Haskell kann ich abstrakten, generischen Code so einfach schreiben wie jede dynamisch typisierte Sprache, die ich verwendet habe. Mein Java/JavaScript-Beispiel oben macht in Haskell no Sinn, da es keine Objekte, Methoden, Ereignisse oder sogar viele Mutationen enthält, aber andere Arten von generischem Code sind wirklich einfach zu schreiben.

Tatsächlich kann Haskell generischen Code schreiben, den dynamisch typisierte Sprachen nicht können. Ein perfektes Beispiel ist die Funktion read, die im Grunde das Gegenteil von toString ist. Sie können ein Int oder ein Double oder einen beliebigen Typ erhalten (sofern es sich um eine bestimmte Typklasse handelt). Sie können sogar polymorph Konstanten haben, so dass maxBound das Maximum Int, Double, Char... usw. Sein kann. , alles abhängig davon, welcher Typ es sein soll.

Meine Theorie ist nun, dass der Produktivitätsgewinn durch die Verwendung einer dynamischen Sprache immer im Vergleich zu Sprachen wie Java mit weniger leistungsfähigen, ausführlicheren und weniger flexiblen Typsystemen) liegt.

Selbst das Typensystem von Haskell weist jedoch einige lästige Probleme auf, die Sie in einer dynamisch typisierten Sprache nicht hätten. Das größte Problem, über das ich mich geärgert habe, ist der Umgang mit Zahlen. Zum Beispiel müssen Sie mit dem Typsystem herumspielen, um length (einer Liste) als Double zu verwenden, etwas, mit dem Sie ohne ein Typsystem keine Probleme hätten. Eine andere nervige Sache, auf die ich gestoßen bin, ist die Arbeit mit Word8 (ein vorzeichenloser int-Typ) und Funktionen, die Int erwarten.

Wenn Sie also letztendlich kein Typsystem haben, ist es einfacher, generischen Code zu schreiben, ohne zu viel nachzudenken, und es werden auch lästige Fallstricke von Typsystemen vermieden. Sie müssen das Typensystem nie in einer dynamischen Sprache bekämpfen, können sich aber auch nicht darauf verlassen.

15
Tikhon Jelvis

F: Ich habe oft die Behauptung gehört, dass dynamisch typisierte Sprachen produktiver sind als statisch typisierte Sprachen. Was sind die Gründe für diese Behauptung? "

Dies hat historische Gründe. Wenn Sie ein paar Jahrzehnte zurückgehen, waren dynamische Sprachen unbestreitbar weitaus produktiver als statische Sprachen (und auch deutlich langsamer). Perl ist eindeutig viel produktiver als C, wenn Sie beide kennen und die anstehende Aufgabe beides zulässt. Aber im Laufe der Zeit haben sich die Sprachen viel voneinander geliehen, und neuere Sprachen verringern die Lücke (sowohl in Bezug auf Produktivität als auch in Bezug auf Leistung).

Hier sind einige Punkte zu beachten:

Garbage Collection: Garbage Collection ist eine enorme Produktivitätssteigerung. Ich glaube Java war die erste statische Mainstream-Sprache mit GC. Vorher bedeutete statisch im Wesentlichen manuelle Speicherverwaltung. (Hinweis: Hier und im Folgenden betrachte ich nur Mainstream-Sprachen. Viele experimentelle Sprachen und es gibt Nischensprachen, die Gegenbeispiele zu jedem Punkt liefern, den ich mache.)

Speichersicherheit: Es ist eine Produktivitätsverbesserung, bei der Sie sich keine Sorgen machen müssen, sich in den Fuß zu schießen. Vor "verwalteten" statischen Sprachen wie Java bedeutete statisch normalerweise direkten Speicherzugriff. Das Debuggen ist auch ein Teil der Produktivität, und unsicherer Speicherzugriff kann zu wirklich undurchsichtigen Fehlern führen.

mständliche Typsysteme. Vor der Einführung parametrisierter Typen (wie Vorlagen oder Generika) in statischen Sprachen waren die Einschränkungen der statischen Typsysteme häufig eine Belastung. Zum Beispiel mussten Sie in Java jedes Mal, wenn Sie ein Objekt aus einer Sammlung auswählten, explizit einen Downcast durchführen. So erhielten Sie den syntaktischen Overhead einer Besetzung und keine Typensicherheit. Angesichts der Tatsache, wie allgegenwärtig Sammlungen in der Programmierung sind, war dies ein großer Nachteil.
Die Deklaration des Typs von allem ist eine Menge redundanter Typisierung, aber mit moderner Typinferenz kann dies erheblich reduziert werden.

Große Standardbibliothek. Python wurde wegen der großen Standardbibliothek bekanntermaßen als "Batterien enthalten" beworben. Dies im Vergleich zu C, das eine sehr minimalistische Standardbibliothek hat. Aber Mit Plattformen wie Java und .net wird eine umfangreiche Standardbibliothek zum Standard, und neuere Sprachen wie Scala und F # erben dies "kostenlos").

Erstklassige Datenstrukturen. Dynamische Sprachen wie Perl und Python haben erstklassige Datenstrukturen wie Listen und Maps mit praktischen syntaktischen Verknüpfungen für allgemeine Operationen eingebaut. Im Vergleich zu In diesem Fall hat C keine integrierten Sammlungen außer Arrays mit fester Größe.

Closures und Lambda-Syntax - Dynamische Sprachen hatten dies normalerweise von Anfang an, aber statische Sprachen haben dies übernommen, zuletzt Java.

REPL Die Fähigkeit, Code-Schnipsel schnell interaktiv zu testen, ist ein großer Segen. Obwohl IDE Tools, wie das "unmittelbare" Fenster in Visual Studio, können statische Sprachen dies bis zu einem gewissen Grad emulieren.

Advanced Tooling - Zusätzlich zu den oben genannten Punkten, an denen statische Sprachen dem Komfort dynamischer Sprachen näher kommen, nutzen moderne Editoren die statische Analyse so, dass dynamische Sprachen nur schwer übereinstimmen können. Zum Beispiel können Editoren sichere automatische Refactorings bereitstellen, was in einer dynamischen Sprache streng genommen unmöglich ist.

Fazit: Historisch gesehen stimmte das, aber heute ist die Antwort weniger eindeutig.


F: Also: Was gibt es für die Produktivität mit dynamischer Typisierung zu sagen, das wirklich ein Vorteil des Typmodells selbst ist?

Es ist etwas schwierig, das dynamische Typisierungsmodell von dynamischen Sprachen zu trennen, aber als Beispiel hat C # im Laufe der Zeit mehr und dynamischere Funktionen übernommen, obwohl es als Kern eine statische Sprache ist. Dies ist wirklich ein Beweis für den Nutzen des dynamischen Typmodells. Beispiele:

Reflexion Reflexion ist grundsätzlich eine dynamische Eingabefunktion. Sie überprüfen Objekttypen zur Laufzeit nach der Kompilierungszeit. Als es eingeführt wurde, war es etwas verpönt, aber in C # wird die Verwendung von Reflexion immer allgegenwärtiger, zum Beispiel verwendet ASP.Net MVC Reflexion stark.

Attribute Attribute sind ein Beispiel für dynamische Typisierung. Sie können einer Klasse zur Kompilierungszeit beliebige Attribute hinzufügen und dann zur Laufzeit (durch Reflektion) prüfen und darauf basierende Objekte bearbeiten. So etwas wie MEP ist im Grunde ein Erweiterungsframework, das auf einem dynamischen Typmodell basiert.

Linq to SQL, EF mv. Die verschiedenen Linq-Transformatoren überprüfen Abfragen als Laufzeitobjekte und generieren SQL im laufenden Betrieb. Dynamischer geht es nicht, als den Code zur Laufzeit zu überprüfen. CodeDom ist die andere Seite der Medaille, auf der zur Laufzeit Code generiert werden kann

Roslyn Roslyn implementiert im Wesentlichen eval, was einst als das bestimmende Merkmal einer wirklich dynamischen Sprache angesehen wurde.

Dynamic Der Typ dynamic- ist das explizit dynamischste Feature in C # und wird angekündigt, um die Interaktion mit externen Objekten und Sprachen einfacher und produktiver zu gestalten. Der Einfachheit halber wird es aber auch in Asp.net MVC verwendet.

Der Vorteil aller oben genannten Funktionen zeigt, dass das dynamische Modell sogar in einer statischen Sprache mit parametrisierten Typen, Strukturtypen und Typinferenz bestimmte Vorteile aufweist .

10
JacquesB

Die Gesamtheit aller modernen Sprachfunktionen ist so groß, dass statisches oder dynamisches Tippen allein nicht viel Gewicht hat.

Die Regel lautet: Je besser Ihre Sprachfunktionen sind, desto kürzer ist Ihr Code. Das ist ganz einfach. Java zeigt, wie die statische Eingabe furchtbar schief gehen kann, was den Gegnern viel zu essen gibt. Schlecht gestaltete Sprachfunktionen sind im Allgemeinen mit Kosten verbunden, und die statische Eingabe in Java ist erstens eine obligatorische Funktion (andernfalls würden die meisten Benutzer sie wahrscheinlich nicht einmal verwenden) und zweitens schlecht ausgeführt.
Deshalb leuchten im Vergleich dazu die meisten dynamischen Sprachen, obwohl ich argumentieren würde, dass PHP Ihr Leben in der Gesamtsumme (zumindest bis vor kurzem) aufgrund vieler nicht wirklich verbessert andere Macken, die nichts mit Typsystemen zu tun haben.

Auf der anderen Seite haben Sie viele Sprachen mit ausdrucksstarken Typensystemen, die Ihnen nicht im Weg stehen und die sogar nicht obligatorisch sind. Einige von ihnen ermöglichen sogar das Einbetten von nicht typisiertem Code, wenn Sie dem Typsystem entkommen müssen.

Persönlich verwende ich haXe, eine Sprache mit Typinferenz, sowohl nominaler als auch struktureller Subtypisierung, optionalem untypisiertem Code, erstklassigen Funktionstypen, algebraischen Datentypen und (nicht ganz ausgereiften, aber äußerst leistungsfähigen) lexikalischen Makros, wobei die arkane Syntax vermieden wird. Nachdem ich haXe seit ungefähr 3 Jahren benutze, bin ich zu einem einfachen Schluss gekommen:

Das Programmieren wird viel einfacher, wenn Ihre Sprache Sie nicht in religiöse Paradigmenentscheidungen einschließt, sondern nur versucht, ein gutes Werkzeug zu sein. Es gibt eine Reihe von statischen und dynamischen Sprachen nd gemischten Sprachen, die dabei erfolgreich sind. Einige von ihnen sind leicht zu erlernen, am schwersten zu meistern.
Ihre Stärke beruht auf der Art und Weise, wie ihre individuellen Merkmale zusammengesetzt werden können, um auf einfache Weise einfache Lösungen für komplexe Probleme zu erstellen. Dies schließt eine gewisse Orthogonalität aus, die nur durch ein empfindliches Gleichgewicht zwischen Einbeziehung oder Auslassung aller bisher untersuchten Sprachmerkmale erreicht werden kann. Wenn Sie versuchen würden, Ruby statische Typisierung hinzuzufügen, würden Sie es verkrüppeln. Wenn Sie versuchen würden, es Haskell zu entfernen, würden Sie es zerstören. Im Gegensatz dazu: Wenn Sie es von C wegnehmen würden, würden die Leute es kaum bemerken, und wenn Sie es von Java wegnehmen würden, könnten sich einige bei Ihnen bedanken.

Aus meiner persönlichen Erfahrung kann ich Ihnen Folgendes sagen: Ich mag Ruby. Es erweiterte meinen Horizont und die Art und Weise, wie ich Systeme entwerfe. IMHO sollte es verwendet werden, um Menschen Programmieren in erster Linie zu lehren. Es ist unauffällig, kraftvoll, prägnant und macht Spaß. Ich verstehe, warum jemand, der aus einer orthodoxen Sprache kommt, es genießen wird.
Auf lange Sicht erlaubt die statische Typisierung jedoch, die Arbeit auf den statischen Analysator zu verschieben, und mit Typinferenz ist dies im Grunde genommen kostenlos. Das Ergebnis ist Code, der einfacher zu warten ist und häufig schneller ausgeführt wird.

Aber auch hier kann statisches Tippen allein nichts bewirken. Es ist eine Frage der Kombination. Ich denke, irgendwo zwischen F #, Scala, Nemerle, OCaml oder HaXe können Sie Ihr eigenes Optimum finden. Aber das hängt letztendlich von Ihnen ab, denn die Sprache sollte es Ihnen ermöglichen, Ihre Gedanken mühelos einzubetten, anstatt Sie zu zwingen, sie darum zu biegen. Und nichts bringt mehr Produktivitätsgewinn, als wenn das Programmieren Spaß macht.

6
back2dos

Persönlich ist der einzige Grund, warum dynamisches Tippen hilfreich ist, wenn Sie ein sehr langsamer Typist sind oder riesige Funktionen/Methoden/was auch immer erstellen, die schwer zu navigieren sind. Sie müssen sich auch mit dem gesamten Thema Unit-Tests befassen. Dynamische Typen erfordern (es sei denn, Sie schreiben gerne fehlerhaften Code) intensive Komponententests (um sicherzustellen, dass Ihre dynamischen Typen nicht unerwartet explodieren (dh die Variable ist meistens Ente, aber manchmal versehentlich dcuk)). Die Statik wird sich viel mehr bemühen, dies zu verhindern (und ja, Sie können das Argument für intensive Komponententests vorbringen).

3
Paul

Ich denke, zuerst müssen Sie "Produktivität" definieren. Was bedeutet "Produktivität" und was beinhaltet es?

Wenn Sie mit "produktiver" weniger Codezeilen schreiben, um dieselbe Funktion zu implementieren, dann sind Programmiersprachen mit dynamischer Typisierung "produktiver" als Sprachen mit statischer Typisierung.

Wenn Sie jedoch auch die Zeit berücksichtigen, die für das Debuggen und die Fehlerbehebung aufgewendet wird, sind Sprachen mit dynamischer Typisierung möglicherweise nicht so produktiv, da Sprachen mit dynamischer Typisierung dazu neigen, die Fehlerprüfung zur Laufzeit zu verschieben, während Sprachen mit statischer Typisierung dagegen verwendet werden kann einige Fehlerprüfungen in der Kompilierungszeit durchführen. Da allgemein angenommen wird, dass die Behebung dieses Fehlers in der Regel umso teurer ist, je später ein Fehler gefunden wird. Daher kann dynamischer Typisierungscode dazu führen, dass die Produktivität im Allgemeinen gleich oder sogar geringer ist als bei statischem Typisierungscode.

0
yaobin