Dynamische Programmiersprachen - Fachgebiet ...
Dynamische Programmiersprachen - Fachgebiet ...
Dynamische Programmiersprachen - Fachgebiet ...
Erfolgreiche ePaper selbst erstellen
Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.
<strong>Dynamische</strong> <strong>Programmiersprachen</strong><br />
Von Lisp und Smalltalk zu Perl, Python, Ruby, Groovy …<br />
Seminar im WS 2008/2009<br />
Prof. Dr.-Ing. Hans-Jürgen Hoffmann<br />
TU Darmstadt, Fachbereich Informatik,<br />
FG <strong>Programmiersprachen</strong> und Übersetzer<br />
Seminarausarbeitung<br />
von<br />
<br />
<br />
<br />
INHALTSVERZEICHNIS 1<br />
Inhaltsverzeichnis<br />
1 Einleitung 2<br />
2 Was versteht man unter Binden ? 3<br />
2.1 Neu-Binden und Mutation . . . . . . . . . . . . . . . . . . . . . . . . 6<br />
2.2 Zeitpunkt des Bindens . . . . . . . . . . . . . . . . . . . . . . . . . . 7<br />
3 <strong>Dynamische</strong> Typisierung / Statische Typisierung 8<br />
3.1 Duck-Typing und die halbdynamische Sprache Boo . . . . . . . . . . . 10<br />
3.2 Vor- und Nachteile bei dynamischer / statischer Typisierung . . . . . . 12<br />
4 Polymorphe Variablen 13<br />
5 <strong>Dynamische</strong>- / Statische-Bindung 14<br />
5.1 Unterschiede zwischen dynamischer und statischer Bindung . . . . . . 18<br />
6 Fazit 19<br />
INHALTSVERZEICHNIS
1 EINLEITUNG 2<br />
1 Einleitung<br />
Das Wort Binden“ (engl. binding) besitzt eine Vielzahl von Bedeutungen und wird in<br />
”<br />
unterschiedlichem Kontext verwendet. So bezeichnet es so unterschiedliche Vorgänge<br />
wie beispielsweise das Zusammenfügen einzelner Seiten zu einem Buch, in der Chemie<br />
das Eingehen einer chemischen Verbindung und vieles mehr. Allgemein bezeichnet Binden<br />
das Herstellen einer Verbindung zwischen zwei oder mehreren Entitäten. In dieser<br />
Seminararbeit geht es um den Begriff Binden im Kontext der Informatik, insbesondere<br />
in Hinblick auf dessen Verwendung bei den <strong>Programmiersprachen</strong>.<br />
Diese Seminararbeit ist wie folgt gegliedert:<br />
Nach einer kurzen Einleitung im 1. Abschnitt wird in Abschnitt 2 versucht, eine kurze<br />
Definition des Begriffs Binden im Kontext der Informatik zu geben und die unterschiedlichen<br />
Bindungsarten vorzustellen.<br />
Der darauffolgende Abschnitt 3 befaßt sich mit den Unterschieden zwischen dynamischerund<br />
statischer Typisierung und dient als Grundlage für das Verständnis der unterschiedlichen<br />
Realisierungsmöglichkeiten für spätes Binden.<br />
Im 4. Abschnitt wird die Verwendung von polymorphen Variablen dargestellt und deren<br />
Zusammenhang mit spätem Binden aufgezeigt.<br />
Abschnitt 5 beschäftigt sich mit dem Zeitpunkt des Bindens und versucht den Unterschied<br />
zwischen frühem und spätem Binden zu verdeutlichen.<br />
Der sich anschließende letzte Abschnitt beinhaltet ein kurzes Fazit.<br />
Grundsätzliche wurde versucht, in jedem dieser Abschnitte die zu vermittelnde und<br />
notwendige Theorie durch möglichst viele Beispiele zu erläutern.
2 WAS VERSTEHT MAN UNTER BINDEN ? 3<br />
2 Was versteht man unter Binden ?<br />
Wie bereits in der Einleitung erklärt wurde, hat das Wort Binden je nach Zusammenhang<br />
eine unterschiedliche Bedeutung. Auch in der Informatik gibt es je nach Kontext<br />
unterschiedliche Definitionen was durch Begriffe wie beispielsweise Namensbindung,<br />
Variablenbindung und Funktionsbindung ausgedrückt wird.<br />
Eine allgemeine Definition für den Begriff Binden“ im Kontext der Informatik kann<br />
”<br />
man beispielsweise in der Wikipedia (siehe [1]) finden: In computer science, binding<br />
”<br />
is the creation of a simple reference to something that is larger and more complicated<br />
and used frequently.“ (In der Informatik bezeichnet der Begriff Binden“ die Erzeugung<br />
”<br />
einer einfachen Referenz zu etwas das größer und komplizierter ist und häufiger benutzt<br />
wird.)<br />
Ein Beispiel hierfür ist das folgende Python-Programm:<br />
Abbildung 1: Beispiel: Binden in Python<br />
In der ersten Zeile des Programms wird eine Funktion mit dem Namen meineFunktion“<br />
”<br />
definiert, die aus 1 Millionen Zeilen Code bestehen soll. Die Python-Anweisung def<br />
gefolgt von dem Namen der Funktion bewirkt, daß der nachfolgende Code (die 1<br />
Millionen Zeilen) mit dem Funktionsnamen assoziert werden, d.h. an diesen gebunden<br />
werden sollen. Der Funktionsname ist damit die einfache Referenz für diese 1 Millionen<br />
Zeilen Code, die ungleich größer und komplizierter sind. Nachdem der Code an den<br />
Funktionsnamen, d.h. an die Referenz dieser Funktion, gebunden wurde, reicht es aus,<br />
wenn man im Hauptprogramm nur noch diesen Funktionsnamen schreibt. Durch das<br />
Schreiben von einer Zeile Code werden 1 Millionen Zeilen Code ausgeführt.<br />
Grundsätzlich bezeichnet der Begriff Binden das Assoziieren von symbolischen Datenreferenzen<br />
mit physikalischen Maschinen-Adressen, d.h. ein symbolischer Bezeichner
2 WAS VERSTEHT MAN UNTER BINDEN ? 4<br />
ist eine Referenz auf eine physikalische Speicheradresse. Binden bezeichnet also das<br />
Verknüpfen eines Namens (Variablenname, Methodenname usw.) mit einer physikalischen<br />
Speicheradresse, d.h. dem Ansprechen von Speicheradressen mit einem Namen.<br />
Dies funktioniert daher auch nicht auf der Ebene der Maschinensprache, da dort keine<br />
Bezeichner mehr vorhanden sind, sondern nur noch die einzelnen Daten in ihrer<br />
Binärdarstellung im Speicher des Rechners vorliegen.<br />
Da in einer Speicheradresse eines Rechners verschiedene Daten, wie beispielsweise Variablen<br />
/ Attribute, Funktion / Methoden usw. abgelegt sein können, kann man auch<br />
all diese an einen symbolischen Namen innerhalb der Programmiersprache, so fern diese<br />
es zulässt, binden.<br />
Ein Beispiel für Funktionsbindung, also das Binden der Speicheradresse an der sich<br />
eine Funktion befindet an eine Variable, ist das untenstehende C-Programm:<br />
Abbildung 2: Beispiel: Funktionsbindung in der Programmiersprache C<br />
In dem obigen Programm werden in den ersten Zeilen zwei Funktionen f1 und f2<br />
definiert, die jeweils den gleichen Rückgabetyp, nämlich int besitzen und die lokale<br />
Integer-Variable x als Übergabeparameter erwarten. Anschließend wird im Hauptprogramm,<br />
das mit der Definition der main-Funktion beginnt, zuerst zwei Integer-Variablen
2 WAS VERSTEHT MAN UNTER BINDEN ? 5<br />
auswahl und x deklariert, wobei die erste die Auswahl des Benutzers im späteren Programmverlauf<br />
speichern und die zweite als Zählervariable innerhalb einer Schleife, die<br />
zur Ausgabe der berechneten Werte auf dem Bildschirm dient, benutzt werden soll.<br />
Danach erfolgt die Deklaration einer besonderen Art von Variablen, eines sogenannten<br />
Funktionszeigers (engl. function pointer).<br />
Ein Funktionszeiger ist eine Variable, in der die Adresse einer Funktion, die sich im<br />
Speicher eines Computers befindet, abgelegt werden kann. Über diese Zeiger-Variable<br />
kann die von ihr referenzierte Funktion im weiteren Verlauf eines Programmes einfach<br />
durch Schreiben des Funktionszeigernamens, d.h. äquivalent zu einem normalen<br />
Funktionsaufruf, aufgerufen werden. Der Funktionszeiger ist also eine Referenz auf eine<br />
Funktion, äquivalent zum Namen der Funktion, jedoch mit dem Unterschied, daß die<br />
Bindung nicht statisch ist, sondern durch Veränderung des Wertes des Funktionszeigers<br />
auf eine andere Speicheradresse während der Laufzeit geändert werden und damit<br />
an eine andere Funktion gebunden werden kann. Funktionszeiger ermöglichen damit<br />
dynamische Bindung an Funktionen.<br />
Im weiteren nicht dargestellten Verlauf des Programms, was durch die drei Punkte<br />
repräsentiert werden soll, wird der Benutzer in einem Menu dazu aufgefordert, entweder<br />
die erste oder die zweite Funktion auszuwählen, von der anschließend eine Wertetablle<br />
im Bereich von 0 bis 10 ausgegeben werden soll. Die Auswahl des Benutzers wird in<br />
der Variable auswahl gespeichert und in der anschließenden if-Bedingung ausgewertet.<br />
Je nachdem ob der Benutzer zuvor die erste oder die zweite Funktion ausgewählt hat,<br />
also abhängig vom Wert der Variablen auswahl wird dem Funktionszeiger func die<br />
Adresse der ersten Funktion f1 oder der zweiten Funktion f2 zugewiesen. Durch diese<br />
Zuweisung wird der Funktionszeiger an die Funktion f1 oder f2 gebunden. Danach kann<br />
durch einfaches Schreiben seines Namens, abhängig von dessen Inhalt, die Funktion<br />
f1 oder f2 aufgerufen werden, was in der nachfolgenden Schleife erfolgt. Innerhalb<br />
der Schleife wird zusätzlich die Schleifenzählvariable x als Parameter der durch den<br />
Funktionszeiger referenzierten Funktion übergeben und anschließend der Rückgabewert<br />
auf dem Bildschirm ausgegeben.<br />
Der gleiche Mechanismus findet sich auch in objektorientierten <strong>Programmiersprachen</strong>,<br />
beispielsweise in C#, als Methodenzeiger (engl. delegate) oder bei Objective-C in Form<br />
von Selektoren wieder.
2 WAS VERSTEHT MAN UNTER BINDEN ? 6<br />
2.1 Neu-Binden und Mutation<br />
Zwei weitere Begriffe, die häufig im Zusammenhang mit dem Begriff Binden verwendet<br />
werden, sind zum Einen das Neu-Binden“ und zum Anderen die Mutation“. Dabei<br />
” ”<br />
versteht man unter Neu-Binden die Änderung eines referenzierenden Bezeichners<br />
währenddessen Mutation die Veränderung eines referenzierten Wertes bezeichnet.<br />
Die Unterschiede zwischen den beiden Begriffen sollen anhand zweier Beispiele in der<br />
Programmiersprache Java verdeutlicht werden:<br />
Abbildung 3: Beispiel: Neu-Binden in der Programmiersprache Java<br />
Im obigen Beispiel wird in der ersten Zeile eine Referenz mit dem Namen list die ein<br />
Objekt vom Typ LinkedList referenzieren kann deklariert. Da in der Programmiersprache<br />
Java Referenzen standardmäßig mit dem Wert null“ 1 . initialisiert werden, wird<br />
”<br />
die Referenz list an den symbolischen Wert null gebunden. In der zweiten Zeile wird<br />
anschließend ein Objekt vom Typ LinkedList erzeugt und mittels des Gleichheitszeichen-<br />
Operators an die Referenz list gebunden. Es hat also ein Neu-Binden stattgefunden. In<br />
der darauf folgenden Zeile wird die Referenz explizit an den Wert null gebunden und<br />
es findet erneut ein Neu-Binden, also eine Änderung des referenzierenden Bezeichners,<br />
statt.<br />
Abbildung 4: Beispiel: Mutation in der Programmiersprache Java<br />
Das obige Beispiel für die Mutation ist bis auf die dritte Zeile mit dem vorhergehenden<br />
Beispiel für das Neu-Binden identisch. In der dritten Zeile jedoch wird durch<br />
1 In einigen <strong>Programmiersprachen</strong> existiert dieser spezielle Wert null oder auch NULL, der von der<br />
Ziffer 0 zu unterscheiden ist. Er hat die Bedeutung leer, unbestimmt, ohne Wert<br />
2.1 Neu-Binden und Mutation
2 WAS VERSTEHT MAN UNTER BINDEN ? 7<br />
das Hinzufügen eines Strings-Objektes in das verkettete Listen-Objekt, das verkettete<br />
Listen-Objekt geändert, d.h. der referenzierte Wert, also das Listen-Objekt LinkedList<br />
ändert sich. Es hat hier also die Veränderung eines referenzierten Wertes stattgefunden,<br />
eine Mutation.<br />
2.2 Zeitpunkt des Bindens<br />
Prinzipiell existieren zwei Zeitpunkte, an denen eine Referenz an ein Objekt gebunden<br />
werden kann. Das ist zum Einen, während der Kompilierung eines Programms und<br />
zum Anderen während der Laufzeit eines Programms. Die erste Möglichkeit, also Binden<br />
während der Kompilierung, wird auch als statische Bindung oder auch als frühes<br />
Binden (engl. static binding bzw. early binding), die zweite Möglichkeit, während der<br />
Laufzeit, als dynamisches oder spätes Binden (engl. dynamic binding bzw. late binding)<br />
bezeichnet.<br />
Unterschiede liegen für den Programmierer vor allen Dingen in der höheren Flexibilität<br />
und besseren Erweiterbarkeit bei Verwendung von dynamischen Binden, da während der<br />
Ausführung eines Programms Veränderungen möglich sind. Teilweise muss jedoch bei<br />
Lösungen die dynamisches Binden verwenden auch mit einer schlechteren Performanz<br />
gerechnet werden, da da der Compiler während der Kompilierung aufgrund der dynamischeren<br />
Natur des Programms weniger Annahmen treffen kann und damit weniger<br />
Möglichkeiten zur Optimierung besitzt.<br />
Um spätes Binden zu erreichen müssen verschiedene Sprachmittel eingesetzt werden.<br />
Diese unterscheiden sich je nachdem ob man eine dynamische Programmiersprache, wie<br />
beispielsweise Smalltalk oder Python, oder eine statische, wie beispielsweise Java oder<br />
C++, verwendet. Bei der Verwendung von dynamischen <strong>Programmiersprachen</strong> lässt<br />
sich spätes Binden durch die Anwendung der dynamischen Typisierung als Sprachmittel<br />
erreichen, während man bei den statischen <strong>Programmiersprachen</strong> das späte Binden<br />
mittels polymorphen Variablen bzw. Methoden ermöglicht werden kann.<br />
In den nachfolgenden zwei Abschnitten soll daher zuerst die Verwendung von dynamischer<br />
Typisierung und polymorpher Variablen gezeigt werden. In dem darauf folgenden<br />
Abschnitt soll dann gezeigt werden, wie man mit Hilfe dieser Sprachmittel spätes Binden<br />
in den unterschiedlichen <strong>Programmiersprachen</strong> ermöglichen kann.<br />
2.2 Zeitpunkt des Bindens
3 DYNAMISCHE TYPISIERUNG / STATISCHE TYPISIERUNG 8<br />
3 <strong>Dynamische</strong> Typisierung / Statische Typisierung<br />
Grundsätzlich bedeutet der Begriff statisch“ in Hinsicht auf <strong>Programmiersprachen</strong>,<br />
”<br />
daß das Binden während des Kompilierens stattfindet und danach keine Veränderungen<br />
mehr möglich sind (siehe [2]).<br />
Im Gegensatz dazu bedeutet dynamisch“ daß während der Ausführung eines Programms<br />
Veränderungen bezüglich des Bindens vorgenommen werden können.<br />
”<br />
In einer statisch typisierten Programmiersprache wie Java oder Pascal, findet Variablenbindung<br />
während des Kompilierens statt. Das bedeutet beispielsweise, daß die<br />
Variablen-Typen, also beispielsweise integer oder string zur Kompilierzeit festgelegt<br />
sind und sich während der Ausführung nicht mehr ändern können. Während des Kompilierens<br />
werden die Variablentypen an einer Stelle des Speichers gebunden. In einer<br />
dynamisch typisierten Programmiersprache wie beispielsweise Smalltalk oder Python<br />
dagegen, sind Variablen nur Bezeichner und deren Typen werden nur durch deren Werte<br />
definiert und nicht durch eine etwaige vorangegangene Typdeklaration. Die Bindung der<br />
verschiedenen Typen an einen Bezeichner erfolgt während der Programmausführung.<br />
Dies soll an dem folgenden Beispiel in der Programmiersprache Python verdeutlicht<br />
werden:<br />
Abbildung 5: Beispiel: <strong>Dynamische</strong> Typisierung in der Programmiersprache Python<br />
In diesem Beispiel ist der Bezeichner b nur ein Variablenname, der während der Laufzeit<br />
immer wieder neu an eine neue Speicherstelle und an einen neuen Variablentypen, zuerst<br />
an einen String und dann an einen Integer-Wert, gebunden wird. Dieses Verhalten ist<br />
möglich, da Python die Fähigkeit zur dynamischen Typisierung als Sprachmittel besitzt.
3 DYNAMISCHE TYPISIERUNG / STATISCHE TYPISIERUNG 9<br />
Es erfolgt im Gegensatz zu einer statischen Programmiersprache wie beispielsweise Java<br />
im Quell-Code keine Typ-Deklaration der einzelnen Variablen.<br />
In einer statisch typisierten Programmiersprache wie Java ist dies, wie das folgende<br />
Beispiel zeigt, nicht möglich:<br />
Abbildung 6: Beispiel: Statische Typisierung in der Programmiersprache Java<br />
Da die Variable b bereits im Kopf des Programms statisch als integer-Variable deklariert<br />
wurde, lässt sich ihr innerhalb der main-Methode kein String-Wert mehr zuweisen.<br />
Es kommt daher zu einem Kompilierfehler. Dies lässt sich sowohl als Nachteil- aber<br />
auch als Vorteil bezüglich des Beispiels mit dynamischer Typisierung betrachten. Ein<br />
Nachteil besteht darin, daß sich der Bezeichner b nicht wiederverwerten lässt, der<br />
Vorteil, daß durch die Typprüfung verhindert werden kann, daß nicht unbeabsichtigte<br />
Wertzuweisungen auftreten können.<br />
Ein weiteres Beispiel für dynamische Typisierung findet man in der Programmiersprache<br />
Objective-C, einer hauptsächlich von Brad Cox in den 80er Jahren bei PPI, später Stepstone,<br />
um die Fähigkeit der Objektorientierung entwickelten Erweiterung der Programmiersprache<br />
C. Deren Syntax und Konzeption der objektorientierten Erweiterungen ist<br />
an Smalltalk angelehnt. Bemerkenswerte Eigenschaften von Objective-C gegenüber der<br />
Programmiersprache C++, die ebenfalls einen Ansatz einer objektorientierten Erweiterung<br />
der Programmiersprache C darstellt (der jedoch auf Simula zurückgeht), sind<br />
u.a. das späte Binden von Methoden und die Typlosigkeit, die beide auf Smalltalk<br />
zurückgehen.<br />
Im unteren Beispiel wird ein Ausschnitt einer Klasse gezeigt, die einen Knoten in einer<br />
einfach verketteten Liste darstellen soll. Dabei ist das Attribut LinkedListNode*<br />
next ein Zeiger auf das nächste Element der Liste und das Attribut id data der Inhalt
3 DYNAMISCHE TYPISIERUNG / STATISCHE TYPISIERUNG 10<br />
den ein Listenelement speichern kann. Damit die Liste jeden beliebigen Typ aufnehmen<br />
kann, ist die Variable data vom Typ id. Id ist in ObjectiveC ein Variablentyp der alle<br />
Objekttypen aufnehmen kann, so daß die Liste alles speichern kann.<br />
Abbildung 7: Beispiel: <strong>Dynamische</strong> Typisierung in der Programmiersprache Objective-C<br />
3.1 Duck-Typing und die halbdynamische Sprache Boo<br />
Ein Beispiel für eine Sprache die sowohl dynamische Typisierung als auch statische<br />
Typisierung unterstützt ist die Programmiersprache Boo. Boo ist eine seit 2003 von<br />
Rodrigo Barreto de Oliveira entwickelte OpenSource-Programmiersprache für das Microsoft<br />
.NET Framework und die Java Virtual Machine (boojay). Die Syntax ist stark an<br />
die von Python angelehnt, da es das ursprüngliche Entwicklungsziel war, eine pythonähnliche<br />
Sprache zu entwickeln, die jedoch auch die Fähigkeit besitzt auf die .NET<br />
und JVM-Bibliotheken zugreifen zu können. Boo ist statisch typisiert, wobei dem Programmierer<br />
das explizite Binden von Variablen an Typen durch Typinferenz und Generische<br />
Typen großteils erspart wird. Daneben wird auch das langsamere, von Ruby<br />
übernommene Duck Typing 2 , also dynamische Typisierung geboten. Dadurch ist sie<br />
2 Duck-Typing ist ein Konzept der Objektorientierung, das die Anwendbarkeit bestimmter Verfahren<br />
nicht an die Ableitung der Klasse von einer bestimmten Superklasse oder der förmlichen Implementierung<br />
einer Spezifikation knüpft, sondern an das Vorhandensein bestimmter Merkmale. Der Name<br />
leitet sich aus einem Gedicht des amerikanischen Schriftsteller James Whitcomb Riley ab. Darin heißt<br />
es: ”When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call<br />
that bird a duck.”[6]<br />
3.1 Duck-Typing und die halbdynamische Sprache Boo
3 DYNAMISCHE TYPISIERUNG / STATISCHE TYPISIERUNG 11<br />
auf der explizit für statisch typisierte Sprachen ausgelegten CLR 3 recht schnell, ohne<br />
auf die Flexibilität einer dynamischen Skriptsprache verzichten zu müssen.<br />
Abbildung 8: Beispiel: Duck Typing in der Programmiersprache Boo[5]<br />
Im obigen Beispiel wird in der ersten Zeile die Variable d als eine Variable vom Typ<br />
duck deklariert. Eine Variable vom Typ duck kann in der Programmiersprache Boo<br />
jeglichen Wert annehmen. In der zweiten Zeile wird der Variablen dann ein Integer-<br />
Wert zugewiesen und in den nächsten Zeilen damit arithmetische Operationen und<br />
eine Bildschirmausgabe durchgeführt. Anschließend wird der Variablen ein String zugewiesen<br />
und anschließend eine String-Operation auf ihr ausgeführt. Wie man erkennen<br />
kann, ist das Verhalten der Variablen nur abhängig davon welchen Wert sie besitzt.<br />
Hier zeigt sich das Prinzip des Duck-Typings: ”<br />
Wenn es geht wie eine Ente, schwimmt<br />
wie eine Ente und quakt wie eine Ente, dann behandle ich es wie eine Ente“ .<br />
3 CLR - die Common Language Runtime ist eine von Microsoft entwickelte Softwareplattform.<br />
Diese umfasst eine Laufzeitumgebung, eine für Programmierer bestimmte Sammlung von Klassenbibliotheken<br />
(API), und angeschlossene Dienstprogramme (Services).<br />
3.1 Duck-Typing und die halbdynamische Sprache Boo
3 DYNAMISCHE TYPISIERUNG / STATISCHE TYPISIERUNG 12<br />
3.2 Vor- und Nachteile bei dynamischer / statischer Typisierung<br />
Grundsätzlich kann man feststellen, daß sich die Vor- und Nachteile bei dynamischer<br />
und statischer Typisierung gegenseitig die Waage halten. Die Vorteile die man bei<br />
statischer Typisierung besitzt sind gleichzeitig aber auch die Nachteile der statischen<br />
Typisierung. Das gleiche gilt umgekehrt auch für die dynamische Typisierung.<br />
Statische Typisierung<br />
• Vorteile:<br />
– bessere Fehlererkennung (während des Kompilierens)<br />
– schnellere Ausführungsgeschwindigkeit der Programme<br />
• Nachteile:<br />
– geringere Flexibilität<br />
– schlechtere Erweiterbarkeit / Wiederverwendbarkeit<br />
<strong>Dynamische</strong> Typisierung<br />
• Vorteile:<br />
– höhere Flexibilität<br />
– bessere Erweiterbarkeit / Wiederverwendbarkeit<br />
• Nachteile:<br />
– schlechtere Fehlererkennung<br />
– langsamerere Ausführungsgeschwindigkeit der Programme<br />
3.2 Vor- und Nachteile bei dynamischer / statischer Typisierung
4 POLYMORPHE VARIABLEN 13<br />
4 Polymorphe Variablen<br />
Statische <strong>Programmiersprachen</strong>, wie beispielsweise Java, können dynamisches Binden<br />
im Gegensatz zu dynamischen Sprachen wie Python, nicht mit Hilfe von dynamischer<br />
Typisierung erreichen, da ihnen dieses Sprachmittel fehlt. Um jedoch trotzdem dynamisches<br />
Binden bei Methoden zu ermöglichen wird dies durch Verwendung von Polymorphie<br />
4 und dabei insbesondere unter Verwendung von polymorphen Variablen und<br />
Methoden erreicht.<br />
Im nachfolgenden Beispiel wird gezeigt, wie ein Drucker-Objekt mittels Verwendung<br />
polymorpher Variablen sowohl an die Variable drucker vom Typ Drucker gebunden<br />
werden kann, als auch an die Variable ausgabegeraet (also an zwei unterschiedliche<br />
Variablentypen und nicht nur an einen bestimmten Typ). Diese Eigenschaft ermöglicht<br />
erst spätes Binden (late binding).<br />
Abbildung 9: Beispiel: Verwendung polymorpher Variablen<br />
Ausgabegeraet ausgabegeraet;<br />
Monitor monitor;<br />
Drucker drucker;<br />
ausgabegeraet<br />
ausgabegeraet<br />
= monitor; // OK<br />
= drucker; // OK<br />
drucker = ausgabegeraet; // nicht OK !<br />
4 Polymorphie (griechisch Vielgestaltigkeit) ist die Fähigkeit eines Bezeichners, der ein Literal oder<br />
eine Variable repräsentieren kann, sich abhängig von seiner Verwendung unterschiedlich darzustellen.<br />
Sie erlaubt es dem Bezeichner, je nach Kontext einen unterschiedlichen Datentyp anzunehmen.
5 DYNAMISCHE- / STATISCHE-BINDUNG 14<br />
5 <strong>Dynamische</strong>- / Statische-Bindung<br />
Statisches Methodenbinden bezeichnet das bereits im zweiten Abschnitt erwähnte statische<br />
Binden eines Bezeichners an eine Methode und ist die Standard-Aufrufweise<br />
bei statischen <strong>Programmiersprachen</strong> wie beispielsweise Java und C++ (zum Beispiel<br />
myObject.myMethod()). Das heißt, es existiert ein direkter Verweis auf die zu verwendete<br />
Methode bzw. Funktion während der Kompilierzeit.<br />
Die Voraussetzungen für statisches Methodenbinden sind zum Einen, daß die aufgerufene<br />
Methode zur Kompilierzeit existiert und deren Signatur dem Compiler bekannt<br />
sein muß und zum zweiten, daß die Bindung an zur Kompilierzeit bekannte Typen,<br />
Interfaces oder Oberklassen erfolgen muß.<br />
Abbildung 10: Beispiel: UML-Diagramm Klassenhierarchie bei Polymorphie
5 DYNAMISCHE- / STATISCHE-BINDUNG 15<br />
Ein Beispiel für dynamisches Binden in Java:<br />
Abbildung 11: Beispiel: <strong>Dynamische</strong>s Binden in Java
5 DYNAMISCHE- / STATISCHE-BINDUNG 16<br />
Bei dynamischer Bindung erfolgt die Bindung nicht durch den Aufruf einer Referenz der<br />
Implementierung, sondern durch das Schicken von Nachrichten an ein Object (message<br />
passing / dynamic dispatch). Das Object selbst schaut dabei zur Laufzeit nach, ob es<br />
eine passende Implementierung (Methode) besitzt, die zur Nachricht passt. Falls es<br />
diese nicht besitzen sollte, kann es entweder eine Fehlermeldung ausgeben oder die<br />
Nachricht an ein anderes Objekt weiterschicken, was als forwarding bezeichnet wird.<br />
Ein Beispiel in Objective-C: Nach dem Beginn der main-Funktion wird eine Variable<br />
namens ausgabegeraet deklariert die vom Typ id ist. Der spezielle Variablen-Typ id<br />
besitzt in Objective-C die Eigenschaft, daß er jedes Objekt binden kann. Durch diese<br />
Art der Typisierung kann dann im weiteren Verlauf des Programmes der Variablen<br />
ausgabegeraet sowohl ein Objekt vom Typ Monitor als auch vom Typ Drucker zugewiesen<br />
werden, da die Variable ausgabegeraet ja vom Typ id ist. Anschließend kann<br />
an die Variable ausgabegeraet dann die Nachricht ausgabe geschickt werden und das<br />
dahinterstehende Objekt (also drucker bzw. monitor) führt die Methode ausgabe anschließend<br />
aus. Es ist kein Polymorphismus nötig wie in Java, da Objective C eine<br />
dynamische Sprache ist.<br />
Abbildung 12: Beispiel: <strong>Dynamische</strong>s Binden in Objective-C
5 DYNAMISCHE- / STATISCHE-BINDUNG 17<br />
Auch bei Python ist, ähnlich wie bei Objective-C, kein Polymorphysmus notwendig<br />
um Late-Binding zu erreichen. In dem folgenden Beispiel werden die Klassen Monitor<br />
und Drucker deklariert, die beide die Methode ausgabe() besitzen. Danach werden<br />
im Hauptprogramm zwei Instanzen (Objekte) der beiden Klassen erzeugt. Anschließend<br />
wird, was aufgrund der dynamischen Typsierung der Programmiersprache Python<br />
möglich ist, einfach einer neu eingeführten Variablen namens ausgabegeraet entweder<br />
das Monitor-Objekt oder das Drucker-Objekt zugewiesen. Daraufhin kann über die<br />
Referenz ausgabegeraet die Methode ausgabe des entsprechenden Objekts aufgerufen<br />
werden.<br />
Abbildung 13: Beispiel: <strong>Dynamische</strong>s Binden in Python
5 DYNAMISCHE- / STATISCHE-BINDUNG 18<br />
5.1 Unterschiede zwischen dynamischer und statischer Bindung<br />
Statisches Methodenbinden ist schneller, da es zum einen keinen Overhead bezüglich<br />
des Methodenaufrufs gibt und zum anderen Inlining 5 möglich ist. Daß kein Overhead<br />
bei statischem Methodenbinden bezüglich des Methodenaufrufs vorhanden ist, ergibt<br />
sich aus der Tatsache, daß der Computer nicht mehr während der Laufzeit des Programmes<br />
suchen muß, wo (Methoden können beispielsweise in Objective-C per forwarding<br />
in anderen Klassen aufgerufen werden) und welche Methode (Methoden können<br />
sich in Ober- oder Unterklassen befinden) er erst aufrufen muss. Dies erfolgt beim<br />
statischem Methodenbinden alles schon während der Kompilierzeit. Dadurch ist außerdem<br />
auch Inlining möglich, was bedeutet, daß der Compiler während des Kompilierens<br />
die komplette Methode an die Stelle des Methodenaufrufs setzt, so daß der Rechner<br />
während der Laufzeit nicht mehr mit großem Aufwand zwischen den Methoden hinund<br />
herspringen muß. Dies macht sich insbesondere innerhalb von Schleifen bemerkbar.<br />
So kann man sich vorstellen, daß sich schon ein erheblicher Unterschied ergibt,<br />
ob der Computer innerhalb einer Schleife, die 1 Million mal ausgeführt wird, zwischen<br />
zwei Funktionen, mit entsprechender Parameterübergabe über den Stack, hin- und herspringen<br />
muß, oder ob der Code der Funktion einfach innerhalb der Schleife eingesetzt<br />
wurde. C++ besitzt das Schlüsselwort inline für Funktionen / Methoden mit dem man<br />
dem Compiler anzeigen kann, daß man die damit markierte Methode / Funktion als<br />
inline-Funktion haben will.<br />
Bei dynamischer Bindung ergibt sich das Problem, daß der Compiler während des<br />
Kompiliervorgangs noch nicht wissen kann, ob und wann eine Methode überhaupt aufgerufen<br />
wird und er auch nicht sagen kann, ob die Übergabe- und Rückgabetypen<br />
überhaupt zueinanderpassen. Das heißt, daß bei dynamischen <strong>Programmiersprachen</strong><br />
eventuell Fehler erst während der Laufzeit auftreten, die in statischen <strong>Programmiersprachen</strong><br />
schon während des Kompilierens auffallen und korrigiert werden können bevor<br />
das Programm ausgeliefert wird.<br />
5 Bei kleinen Unterprogrammen fällt der Aufwand zum Aufruf des Unterprogrammes verglichen<br />
mit der vom Unterprogramm geleisteten Arbeit stärker ins Gewicht. Daher versuchen Compiler, den<br />
Maschinencode kleinerer Unterprogramme direkt einzufügen. Diese Technik wird auch als Inlining<br />
bezeichnet. In manchen <strong>Programmiersprachen</strong> ist es möglich, durch inline-Schlüsselwörter den Compiler<br />
darauf hinzuweisen, dass das Einfügen von bestimmten Unterprogrammen gewünscht ist. Das<br />
Einfügen von Unterprogrammen eröffnet oft, abhängig von den Parametern, weitere Möglichkeiten<br />
für Optimierungen.<br />
5.1 Unterschiede zwischen dynamischer und statischer Bindung
6 FAZIT 19<br />
6 Fazit<br />
In dieser Seminarbeit wurde versucht die Begriffe dynamisch“ und statisch“ im Kontext<br />
von <strong>Programmiersprachen</strong> und des Zeitpunkt des Bindens darzulegen. Weiterhin<br />
” ”<br />
sollten die Vor- und Nachteile von dynamischer - und statischer Typisierung aufgezeigt<br />
und deren Verwendung als Sprachmittel in Hinsicht auf die Realisierung von<br />
frühem und spätem Binden gezeigt werden. Auch sollte gezeigt werden, daß man den<br />
grundsätzlichen Widerspruch zwischen den Vor- und Nachteilen von dynamischer und<br />
statischer Programmierung nicht auflösen kann und sich je nach Anwendung für die<br />
für das Projekt passende Variante entschieden werden muss.<br />
Grundsätzlich kann man festhalten, daß, wenn man auf die Performanz der Ausführung<br />
und eine bessere Fehlererkennung der Programmen Wert legt, man statische Programmierung<br />
bevorzugen sollte, falls höhere Flexibilität, Erweiterbarkeit und Produktivität<br />
gewünscht wird, dynamische Programmierung.
LITERATUR 20<br />
Literatur<br />
[1] Binding (computer science) - Wikipedia<br />
http://en.wikipedia.org/wiki/Binding (computer science)<br />
Zugriffsdatum: 02.12.2008<br />
[2] Dai, L.: Static and Dynamic Behavior<br />
http://www.seattleu.edu/dingle/web/510/chapter11.ppt<br />
acstaff, 2007<br />
Zugriffsdatum: 02.12.2008<br />
[3] Anonymous: Dynamic binding, binding evaluation contexts, and (delimited) control<br />
effects<br />
http://www.okmij.org/ftp/Computation/dynamic-binding.html<br />
okmij.org, 2007<br />
Zugriffsdatum: 02.12.2008<br />
[4] H.-C. Stotts: Dynamic Method Binding, Inheritance<br />
http://www.rockfish.cs.unc.edu/COMP144/lect24a.ppt<br />
University of North Carolina, 2007<br />
Zugriffsdatum: 02.12.2008<br />
[5] Rodrigo Barreto de Oliveira: Boo Tutorial Part 18 - Duck Typing<br />
http://boo.codehaus.org/Part+18+-+Duck+typing<br />
Zugriffsdatum: 02.12.2008<br />
[6] Duck-Typing - Wikipedia<br />
http://de.wikipedia.org/wiki/Duck-Typing<br />
Zugriffsdatum: 02.12.2008<br />
LITERATUR
ABBILDUNGSVERZEICHNIS 21<br />
Abbildungsverzeichnis<br />
1 Beispiel: Binden in Python . . . . . . . . . . . . . . . . . . . . . . . . 3<br />
2 Beispiel: Funktionsbindung in der Programmiersprache C . . . . . . . . 4<br />
3 Beispiel: Neu-Binden in der Programmiersprache Java . . . . . . . . . 6<br />
4 Beispiel: Mutation in der Programmiersprache Java . . . . . . . . . . . 6<br />
5 Beispiel: <strong>Dynamische</strong> Typisierung in der Programmiersprache Python . 8<br />
6 Beispiel: Statische Typisierung in der Programmiersprache Java . . . . 9<br />
7 Beispiel: <strong>Dynamische</strong> Typisierung in der Programmiersprache Objective-C 10<br />
8 Beispiel: Duck Typing in der Programmiersprache Boo[5] . . . . . . . 11<br />
9 Beispiel: Verwendung polymorpher Variablen . . . . . . . . . . . . . . 13<br />
10 Beispiel: UML-Diagramm Klassenhierarchie bei Polymorphie . . . . . . 14<br />
11 Beispiel: <strong>Dynamische</strong>s Binden in Java . . . . . . . . . . . . . . . . . . 15<br />
12 Beispiel: <strong>Dynamische</strong>s Binden in Objective-C . . . . . . . . . . . . . . 16<br />
13 Beispiel: <strong>Dynamische</strong>s Binden in Python . . . . . . . . . . . . . . . . 17<br />
ABBILDUNGSVERZEICHNIS