Statische Oder Dynamische Typisierung
 
StartSeite | Neues | TestSeite | ForumSeite | Teilnehmer | Kategorien | Index | Hilfe | Einstellungen | Ändern

Programmiersprachen unterscheiden sich teilweise sehr stark in der Art und Weise, wie sie mit dem Datentyp von Variablen umgehen. Zwischen den Extremen "statische Typisierung" und "dynamische Typisierung" scheint es mir auch noch Abstufungen zu geben, die eine Diskussion wert wären.

Große Teile dieser Seite setzen statische Typisierung mit dem Typsystem und der expliziten Typisierung wie in C++ und Java gleich. Wenn das richtig wäre, gäbe es keine Diskussion... aber es gibt auch bessere statische Typsysteme.


Vorteile statischer Typisierung:

Typische Vertreter: SpracheHaskell, SpracheModula3, SpracheOberon, SprachePascal, SpracheAda, SpracheEiffel, SpracheSatherK, SpracheFortran, SpracheCee, SpracheCpp, SpracheJava....


Vorteile dynamischer Typisierung:

 name = names.next();
statt
 String name = (String)names.next();
Wer hätte gedacht, dass ein Name eine Zeichenkette ist...?
Nummer 5 lebt ...
Typische Vertreter: SpracheSmalltalk, SprachePython, SprachePerl, SpracheRuby, SpracheTcl, SpracheRexx?, SpracheRebol?, ...


Mischformen:

Jüngere MS Basic-Versionen enthalten an sich das typische Spektrum an Datentypen (int, long, float, double, string, "objekte"), zusätzliche jedoch den Datentyp "Variant", der mit all diesen Datentypen verträglich ist. Erst wenn eine Variant-Variable verwendet wird, entscheidet sich, ob die Verwendung eventuell zu einem Runtime-Error führt.

Objektorientierte Programmierung, speziell das dynamische Binden, hat die Vor- und Nachteile dynamischer Typisierung auch zu ansonsten sehr streng typisierten Sprachen gebracht. In dem in C++ geschriebenen Schnittstellengenerator SWIG zum Beispiel wird die dynamische Typstruktur der SprachePython nachgebildet, so dass man dort mit C++ wie mit einer untypisierten Sprache arbeitet. Templates sind dagegen eine rein statische Angelegenheit.

Statische Typisierung ist nicht gleich statische Typisierung. In der SpracheModula3 wird zum Beispiel streng zwischen Wahrheitswerten, Bitfeldern, ganzen Zahlen, Aufzählungen und Zeichen unterschieden, im Gegensatz zu der SpracheCee, wo diese Typen alle mit ganzen Zahlen gleichgesetzt werden. Auch dynamische Typisierung ist nicht gleich dynamische Typisierung. Da gibt es zum einen Sprachen wie die SprachePython, die dynamisch immerhin noch zwischen Fließkommazahlen, ganzen Zahlen, Zeichen und Texten etc. unterscheiden. Zum anderen gibt es Sprachen, wie die SpracheTcl und die SpracheRexx?, die das alles durch Texte dargestellen. Wenn man die genannten Sprachen also nach absteigender Strenge (und damit Typsicherheit) sortiert, kommt man hier auf die Reihenfolge: SpracheModula3, SpracheCee, SprachePython, SpracheRexx?.


Siehe auch
Diskussion
siehe StatischeVersusDynamischeTypisierung und allgemeiner bei TypSicherheit

Dass dynamische Typisierung CodeRefactoring erleichtert, ist womöglich falsch, siehe Argumentation auf WardsWiki:BenefitsOfDynamicTyping. Wäre schön, wenn derjenige, der die Behauptung verzapft hat, die Sache nochmal durchdenkt. -- VolkerGlave

Ich bin derjenige, der diese Behauptung "verzapft" hat. Wobei das nicht ganz richtig ist, da ich so gut wie keine Erfahrung mit Refactoring in dynamischen Sprachen besitze. Die Aussage stammt von Personen, die ich als Autoritäten für OO-Entwicklung in beiden Arten von Sprachen bezeichnen würde. Dies, und meine eigenen Erfahrungen mit Problemen beim Refaktorisieren in Java lassen mich annehmen, dass diese Aussage zutrifft. Ich bin jedoch gerne bereit, spezifische Bedenken und insbesondere anderslautende Erfahrungen zu diskutieren. -- IljaPreuß

Ist das nicht vor allem ein kulturelles Problem? Meine Vermutung, basierend auf eigenen Erfahrungen, ist die: Refactoring funktioniert nur in einer Umgebung mit ausreichend Regressionstests. Es kommt ziemlich oft vor, dass ein vermeintlich idiotensicheres Refactoring kein echtes Refactoring sondern ein fehlerbehaftetes Umschreiben ist. Außerdem benötigt man vernünftige Werkzeuge. Der RefactoringBrowser von SpracheSmalltalk führt intern Manipulationen an einen Parsebaum durch und nicht etwa einfache Textersetzungen. Eine Sprache, deren Compiler in der Sprache selbst geschrieben ist, bietet Toolentwicklern beste Voraussetzungen. Eine statisch typisierte Sprache liefert dagegen mehr Ansatzpunkte für ausgefeitle Refactorings. Oft will dann aber jemand mit diesem mühsam entwickelten neuen Werkzeug Schotter machen (z. B. gibt es bis heute keinen kostenlosen Lint für C++). Dann wäre da noch der Turnaround-Zyklus. Welche Zeit bin ich bereit, nach einer Kleinständerung auf Compiler, Linker und das Durchlaufen der Regressiontests zu warten? In dynamisch typisierten Sprachen ist das eine Sache von wenigen Minuten, denn das Compilieren, Linken und evtl. sogar das Laden der Testdaten entfällt. -- SDö

Ewig dieselben Kamellen. Ja, mit dynamisch typisierten Sprachen lassen sich Programme in Sekundenschnelle verändern und sind dann trotzdem noch ablauffähig, wenn auch nicht mehr funktionsfähig (was nur Kleingeister stört). -- vgl

Solange Du keine ausreichenden Tests hast, hast Du vermutlich recht - in einer statisch typisierten Sprache ist dann die Wahrscheinlichkeit höher, dass das Programm zumindest noch durchläuft und vielleicht sogar noch einigermaßen das macht, was es machen soll. Ich verlasse mich da aber lieber auf Tests, und *die* machen dann die statische Typisierung wieder weniger wertvoll.

Allerdings finde ich es schon imposant, was moderne Tools wie Eclipse und IDEA mit den statischen Typinfos anfangen können. Keine Ahnung, wie es da in dynamisch typisierten Sprachen aussieht. -- IljaPreuß

"Ewig dieselben Kamellen." Nein Volker, ich gebe dir ausdrücklich recht, dass Typinformationen prinzipiell das Refactoring erleichtern müssten. Und es ist beileibe nicht so, dass alle dynamisch typisierten Sprachen vernünftige Refactoring-Werkzeuge mitbringen. In Smalltalk funktioniert das Refactoring, weil die IDE einen effizienten Zugriff auf die gesamte Codebasis und den Bytecode-Compiler ermöglicht. Die Werkzeuge sind da und werden benutzt. Python und Ruby wollen da auch hin, jedoch ohne dabei ihre Scripting-Qualitäten einzubüßen. Eclipse hat mir vor einem Jahr noch nicht wirklich gefallen, aber da tut sich angesichts der vielen Java-Entwickler eine Menge. Außerdem möchte ich mal vermuten, dass IBM und OTI (siehe VisualAge) einiges an Know-How beisteuern. Auch für C++ sehe ich einen leichten Silberstreif am Horizont: Ach die gcc-Entwickler steuern inzwischen mit vorkompilierten Header-Dateien und Verbesserungen in der Template-Verwaltung den irren Compilezeiten entgegen. -- SDö


C, Pascal und Verwandte sind eigentlich keine typischen Vertreter statisch getypter Programmiersprachen mehr. Ordentliche Typsysteme sind polymorph und bei ihnen geht es nicht mehr (nur) darum, wie viele Bits ein Datum braucht, sie sind eher ein Deduktionssystem, das partielle Korrektheit eines Programm zu beweisen sucht. Typische Vertreter dafür sind ML und Haskell. In dem Sinne:

 String name = (String)names.next();
Wer hätte gedacht, dass ein Name eine Zeichenkette ist...?

Na ich nicht. Ein Name ist ein Name, und das ist ein anderer Typ als ein String. Eine Adresse ist auch eine Adresse und kein String, und damit auch etwas anderes als ein Name. Dasselbe gilt für einen HTML-Quelltext. Sicher, alle diese Typen sind in gewisser Weise isomorph, aber dennoch verschieden! Damit gehen viele Dinge im Programm nicht mehr (Name und Adresse versehentlich vertauschen oder HTML-Quelltext versehentlich dem User anzeigen), aber die wären eben sowieso alle falsch gewesen.

Das ist jetzt aber keine Frage von statischer oder dynamischer Typisierung mehr. Wenn Du Dir in einer dynamisch typisierten Sprache einen Typ Name definierst, kannst Du dem auch keine Adresse mehr zuweisen. Und auch da finde ich

name = names.next()

eleganter als

Name name = (Name) names.next()

Ja, stimmt im Prinzip. Die Einführung isomorpher Typen bringt aber in einer dynamisch getypten Sprache weniger: Zum einen ist der Dokumentationseffekt weg. In Haskell schreibe ich eben sowas wie

 enterEmployee :: Database -> Name -> Address -> IO() 

(:: ist der hat-den-Typ-Operator und ist fast überall erlaubt, oft guter Stil, aber nur selten wirklich notwendig; IO() bezeichnet eine Funktion mit Seiteneffekten und ohne direktes Ergebnis) und brauche die Parameter eigentlich nicht mehr benennen, denn der Typ sagt bereits alles und stimmt immer, schließlich rechnet der Compiler nach. Dasselbe geht bei dynamischer Typisierung nur mit Kommentaren, und driften schnell vom Code ab. Zweitens tue ich sowas natürlich, um möglichst früh über dumme Fehler informiert zu werden, zum Beispiel wenn ich das Datenbankhandle mal wieder an letzter Stelle übergeben habe. Der Compiler meckert sofort, eine Sprache wie Lisp oder Smalltalk erst zur Laufzeit, wenn dieser Code-Zweig wirklich getestet wird, und eine wie Perl... naja, reden wir nicht drüber.

Was das Ding in Java betrifft

 Name name = (Name) names.next() 

das ist das übelste, was man sich vorstellen kann. Der Typecast ist nötig, weil (Begründung aus C++-Programmiersicht) diese Sprache keine polymorphen Funktionen kennt oder (Begründung aus Smalltalker-Sicht) weil diese Sprache dazu zwingt, offensichtliche Type zu deklarieren, und zwar zweimal. Nö, Java ist echt kein gutes Argument für irgendwas. In Haskell schreibe ich dieses Statement tasächlich ohne Angabe irgendeines Typs, die next-Methode hätte eine explizite Typdeklaration, und sie wäre polymorph, und names hätte wahrscheinlich einen expliziten Typ. Letzteres ist gut so, weil diese Deklaration wirklich eine Intention des Programmierers ausdrückt, von der der Compiler durchaus erfahren sollte. Das ist auch echt keine Mehrbelastung.

Man sollte das Typsystem einfach zum eigenen Vorteil ausnutzen -- und das klappt auch. EIn Programm, dass man am Typchecker von Haskell verbei gebracht hat, läuft nahezu immer auf Anhieb wie gewünscht. Ein C-Programmierer glaubt einem das nicht, aus naheliegenden Gründen.

Ich kann Dir das auch nicht so recht glauben. Nach meiner Erfahrung ist nicht allzu schwer Bugs zu produzieren, ohne Typfehler zu bemühen...

Probier es aus, ich hätte es sonst auch nicht geglaubt ;)

In C++ habe ich mehr als einmal die vergleichbare Erfahrung gemacht, daß die Einführung von const correctness sogar Designfehler aufdecken kann. Das Geheimnis statischer Typisierung ist eigentlich trivial: Je genauer ich mich ausdrücke, desto weniger Raum für Mißverständnisse bleibt; ob zwischen Autor und Compiler oder zwischen Autor und Codenutzer/-pfleger. -- FreddyTheCat

Imho gehören zu einem vernünftigen Typsystem mindestens die Templates von C++ (oder etwas vergleichbares, dafür aber durchdachtes). Übrigens bedeutet statische Typisierung nicht, dass der Programmierer alle Typen explizit angeben muß, um sich das (soweit angebracht) zu ersparen, gibt es HindleyMilnerTypInferenz.

Auch in Smalltalk werden gelegentlich Rufe nach Typinformationen a la der Java Interfaces laut. Aber nicht, weil Smalltalker statische Typprüfungen einführen wollen, sondern weil man häufig wirklich soetwas wie einen Typ für Methodenparameter im Sinn hat. Interfaces haben sich in Smalltalk aber nie durchgesetzt. Man möchte vorhandene Informationen nicht verschenken ohne sich jedoch in der Flexibilität einzuschränken. Typen werden also eher kommentiert. Bei Templates habe ich das wiedergefunden. Zwar erfolgt hier die Prüfung statisch, Typen sind hier aber ebenfalls anonym.`

Du meinst hier sicherlich C++-Templates? In Java-Templates werden die Typen nicht anonym sein.

Was einem wirklich hilft, ist eine IDE, die die implizite Typinformation mit einer Codebasis vergleicht und eine Liste der den Typ implementierenden Klassen verfügbar macht. In Ansätzen habe ich soetwas im RefactoringBrowser oder in CaseTools schon gesehen. Aber noch nie voll integriert. -- SDö


Stimmt tatsächlich, unter Umständen. Eine dynamisch typisierte Sprache muß mit jedem Datum eine Typkennung herumschleppen. Sie muß zudem eine Aufrufkonvention besitzen, bei der alle Daten kompatibel sind, und das heißt praktisch, Zeiger zu übergeben. Dynamische Typisierung bedeutet also grundsätzlich eine Indirektion, Heapallokation für wirklich alles und Speicheraufwand für Typinformation. Java macht extra eine Ausnahme für eingebaute Typen, um den Overhead zu verringern (was die Sprache ziemlich kaputt macht, aber ist ja egal.)

Hat man ein statisches Typsystem, kann man den Overhead manchmal einsparen. Kennt man die Aufrufkonvention einer Funktion, kann man Daten direkt übergeben, ohne Indirektion. Man kann auch Daten in Datenstrukturen direkt einbetten, statt durch Zeiger auf sie zu verweisen. Der Glasgow Haskell Compiler erlaubt sowas (als Extension gegenüber Haskell 98), und der Gewinn sowohl an Rechenzeit als auch an Speicherplatz ist zuweilen signifikant. Besonders numerische Algorithmen (man stelle sich eine große Matrix voller Zahlen vor) profitieren ganz gewaltig.

Aber Java ist doch statisch typisiert?

nur mit dem schwachen Typsystem von C, obwohl es offensichtlich eher dynamisch ausgelegt ist, wie Smalltalk. Siehe dazu auch den oben bereits genannten Link http://www.pragmaticprogrammer.com/cgi-local/pragprog?JavaIsUntyped


Zum Beitrag von Martin Fowler: http://martinfowler.com/bliki/DynamicTyping.html

Der Mann hat recht und versucht nicht, die Vorteile von statischer Typisierung herunterzuspielen. Was er braucht ist die SpracheHaskell. Kompakter Code, statische Typpolymorphie und statische Typsicherheit. Wenn man von der SpracheCpp zu einer Sprache wie der SprachePython wechselt, wird man natürlich keinen Rückschritt merken, weil die maschinennahen Typen bei C++ kaum differenziert sind. -- HenningThielemann


KategorieProgrammierSprachenKonzepte KategorieDiskussion
StartSeite | Neues | TestSeite | ForumSeite | Teilnehmer | Kategorien | Index | Hilfe | Einstellungen | Ändern
Text dieser Seite ändern (zuletzt geändert: 19. Dezember 2006 14:53 (diff))
Suchbegriff: gesucht wird
im Titel
im Text