Seminar Übersetzung von künstlichen Sprachen
Übersetzung objektorientierter Sprachen
André ChristMünster, 5. Januar 2007
2 / 30
Gliederung
1. Objektorientierte Konzepte2. Übersetzung
1. Klassen und Methoden2. Vererbung3. Parametrisierung
3. Zusammenfassung & Fazit
1. Objektorientierte Konzepte 3 / 30
Objektorientierte Programmierung
Dr. Alan Kay: „Objektorientierte Programmierung“Austausch von Nachrichten zwischen Objekten
ObjekteZustand: InstanzvariablenVerhalten: MethodenIdentität: Bei Erzeugung (Instanziierung) festgelegt (new)
NachrichtenAnfrage, eine Operation auf einem Objekt auszuführenZur Laufzeit wird „passende“ Methode ausgewählt und ausgeführtSyntax z.B.: obj.m() oder obj->m()
1. Objektorientierte Konzepte 4 / 30
Klassen und Methoden
KlasseBeschreibt Menge von Objekten gleicher Struktur (Methoden, Instanzvariablen)Klassendefinition: Instanzvariablen und MethodenFührt neuen Datentyp ein
MethodenMögliche Operationen eines ObjektsVergleichbar mit Funktionen (Prozeduren) aus imperativen SprachenAber: Können auf Instanzvariablen ihres Objekts zugreifen (this)
public class IntStack { private int size; // Instanzvariable private int[] data; // Instanzvariable
public int pop() { // Methode return this.data[this.size – 1]; this.size--; }}
1. Objektorientierte Konzepte 5 / 30
Vererbung
VererbungB erbt von A: Alle Instanzvariablen und Methoden einer Superklasse A in der Unterklasse B enthaltenSpezialisierung
Unterklasse kann Instanzvariablen und Methoden hinzufügenImplementierung geerbter Methoden änderbar (Signatur gleich Invariante Spezialisierung)
Einfachvererbung (1 Superklasse, V-Baum)Mehrfachvererbung (n Superklassen, V-Graph)
Teiltypregela,b Variablen der Klassen A, BZuweisung a = b gültig, falls A und B identisch oder B Unterklasse (auch indirekt) von AZugriff nur über in A definierte Schnittstelle (A-Sicht auf B)
Figur
Flaeche()
Kreis
Flaeche()
Radius()
1. Objektorientierte Konzepte 6 / 30
Polymorphie
Polymorphie („Vielgestaltigkeit“)Variablen, Datenobjekte sowie Argument- und Rückgabewerte können mehr als einen Datentypen annehmenPrinzip nicht auf objektorientierte Sprachen beschränktPolymorphie insbesondere auch bei funktionalen Sprachen
KlassifikationSubklassen-PolymorphieParametrische-PolymorphieÜberladenCoercion
Universelle-Polymorphie
Ad hoc-Polymorphie
Nach: Strachey / Cardelli, Wegner
1. Objektorientierte Konzepte 7 / 30
Subklassen-Polymorphie
Anwendungsfall: Plugins / FrameworksMethoden-Auswahlregel
Ein Objekt einer Unterklasse B von A kann im Superklassenkontext von A verwendet werdenMethode m wird in Unterklasse überschriebenMethode m muss auch dann ausgeführt werden, wenn das Objekt B in Variable vom Typ A vorliegt (A-Sicht auf B)
Figur
Flaeche()
Kreis
Flaeche()
public class Kreis extends Figur {…}
Kreis k = new Kreis();k.Flaeche(); // Kreis::Flaeche()
Figur f = new Kreis(); // Superklassenkontextf.Flaeche(); // Kreis::Flaeche()
Erst zur Laufzeit bestimmbar, welche Instanz die Verarbeitung einer Nachricht übernimmt
1. Objektorientierte Konzepte 8 / 30
Parametrische-Polymorphie
Motivation: Gleiche Funktionalität für mehrere Datentypen notwendig (insb. Datenbehältern)Bisher (Unsicherer Cast / Typüberprüfung)
Generische Klasse mit formalem Parameter T
Instanziierung mit aktuellem Parameter String:
public class Stack<T> { public void push(T element) {…} public T pop() {…}}
Stack oldStack = new Stack();oldStack.push(new Integer(2));String top = (String) oldStack.pop(); // Unsafe Downcastif (oldStack.pop() instanceof String) // instanceof type check
Stack<String> stringStack = new Stack<String>();stringStack.push("Hello World");String top = stringStack.pop();
9 / 30
Gliederung
1. Objektorientierte Konzepte2. Übersetzung
1. Klassen und Methoden2. Vererbung3. Parametrisierung
3. Zusammenfassung & Fazit
2. Übersetzung 10 / 30
Übersetzung
Aufspaltung des ÜbersetzungprozessesAbstrakte Maschine: Zwischencode, an Quellsprache angepasstReale Maschine: Maschinencode, durch Prozessorarchitektur bestimmt (Weit verbreitet: CISC und RISC)
Abstrakte Maschine für objektorientierte SpracheProgrammspeicher (Zwischencode)Befehlsinterpreter (Ausführung des Zwischencodes)Stack (Methodeninkarnationen in Frames)Heap (u.a. Instanzen von Klassen)
Virtuelle Maschine für objektorientierte SpracheAusführungsumgebung moderner obj. Sprachen C# / JavaAusprägung einer abstrakten MaschineAusführung des Zwischencodes zur Laufzeit des Programms
2. Übersetzung 11 / 30
Befehls-zähler
Framepointer
Register
Hilfspeicher Frame
Frame
Object 1
Object 2
...
Object n
Klassen-deskriptorKlassen-deskriptor
...
Methoden-rumpf
Methoden-rumpf
...Main()
Programmspeicher
Befehls-interpreter
Stack
Heap
ObjektInstvar 0
Instvar 1
...
Instvar n
Objekt
Objekt
...
VirtuelleMethodentabelle
Abstrakte Maschine
Befehlszähler: Zeigt auf abzuarbeitenden Befehl in MethodenrumpfFramepointer: Verweist auf den Frame (lokale Variablen einer Methode) einer Methodeninkarnation (passend zu Befehlszähler)
In Anlehung an: Bauer, Höllerer 1998
Verweis (Zeiger)
1
2
3
45
6
0
2. Übersetzung // Klassen und Methoden 12 / 30
KlassendeskriptorMethodentabelle: Indizierte Datenstruktur mit Methodenselektoren (Namen)
Methodenselektor verweist auf entsprechenden Methodenrumpf im Methodenarray
ClassFile { // Referenz auf Superklasse u2 super_class;
// Anzahl Instanzvariablen u2 fields_count;
// Name u. Typ d. Instanzvar. field_info fields[field_count];
// Anzahl der Methoden u2 methods_count;
// Methodentabelle method_info methods[methods_count]; […]}
Klassendeskriptor
Methodenarray
Superklasse
Methoden-tabelle
# Instanz-variablen
# Methoden
Methoden-array
Methoden-Selektor 1Methoden-Selektor 2
...
Methoden-Selektor n
Methodentabelle
Methoden-rumpf 1
...
Methoden-rumpf n
Methoden-rumpf 2
In Anlehung an: Bauer, Höllerer 1998
Auszug aus Java-class Datei:Detaillierung Klassendeskriptor:
2. Übersetzung // Klassen und Methoden 13 / 30
Übersetzung von Methoden (1)
Methodenrumpf im Wesentlichen wie Funktions- oder Prozedurrümpfe imperativer Sprachen
Variablen, Schleifen, Verzweigungen...
Objektorientierte Sprachkonstrukte (in Methoden)Senden einer Nachricht: Object.message() (auch O->m())
Zugriff auf Instanzvariable: Object.variable (auch O->v)
Selbstreferenz: this (auch self)this.message() / this.variable
Zugriff auf Superklasse: super (auch parent)super.message() / super.variable
2. Übersetzung // Klassen und Methoden 14 / 30
Übersetzung von Methoden (2)
Realisierung der Selbstreferenz thisMethode m einer Klasse K <ret> m(<args>)Übersetzt als Funktion: <ret> Km(K this, <args>)
Nachricht m an Objekt o vom Typ K: <ret> o.m(<args>)Umgewandelt in Funktionsaufruf: <ret> Km(o, <args>)
Methodennamen -> FunktionsnamenProblem: Globaler Namensraum von FunktionenFunktionen müssen sich in ihrem Namen unterscheidenCodierungsschema: _ZN#<Klasse>#<Methode>E<Typ>* (GNU G++ 3.0)
Abbildung auf Konzept von Funktionen / Prozeduren imp. Sprachen
Stack::push(int element) _ZN5Stack4pushEiStack::push(float element) _ZN5Stack4pushEfStack::push(float comp, float imag) _ZN5Stack4pushEff
2. Übersetzung // Vererbung 15 / 30
Methodenaufrufe
Statisches Binden (imp. Prozedur- und Funktionsaufruf)Funktionsaufruf wird zur Übersetzungszeit der Definition der Funktion zugeordnetNach Typüberprüfung von Argument- und Rückgabewerten legt Übersetzer relative Speicheradresse fest
Dynamische Bindungsregel„Überschreibt eine Klasse B eine Methode ihrer Superklasse A und wird eine Nachricht m an ein Objekt geschickt, dessen Klassenzugehörigkeit zur Übersetzungszeit nicht bekannt ist, so muss die Methodenimplementierung zur Laufzeit an das Objekt gebunden werden.“
Bauer, Höllerer 1998
2. Übersetzung // Vererbung 16 / 30
Dynamisches Binden mittels vtable
Virtuelle Methodentabelle (vtable)In C++ auch virtuelle FunktionstabelleSog. virtuelle Methoden in Unterklassen überschreibbarEinträge in der vtable verweisen auf MethodenimplementationenSichten: Offsets in der vtable (siehe geschweifte Klammern)
2. Übersetzung // Vererbung 17 / 30
Realisierung vtable in C++
f : Figur
virtual Flaeche()
r : Rechteck
Flaeche() 0:Rechteck::Flaeche()
vtable
1:Rechteck::Ecken()
0:Rechteck::Flaeche()
vtable
1:Rechteck::Ecken()
Ecken()
2:Quadrat::Kante()
q : Quadrat
Kante()
InstanziierungQuadrat q = new Quadrat();Objekt erhält Zeiger auf vtable seiner Klasse
Methodenaufrufq->Flaeche();In der vtable wird Adresse der Funktionsimplementation nachgeschlagenEffiziente Implementation durch Funktionszeiger in C:
Standardisierte Indezierung der vtableUmwandlung der Methodenaufrufe:q->Flaeche() (*(q->vtable[0]))()
2. Übersetzung // Vererbung 18 / 30
0:Rechteck::Flaeche()
vtable
1:Rechteck::Ecken()
2:Quadrat::Kante()
q : Quadrat
Kante() FigurRechteck
Quadrat
Realisierung vtable in C++
Subklassen-PolymorphieQuadrat q = new Quadrat();Rechteck f = (Rechteck) q;f->Flaeche();Sicht über vtable des Objekts vom Typ Quadrat
2. Übersetzung // Vererbung 19 / 30
Mehrfachvererbung
Diamant Problem (Auszug)Wiederholte Beerbung: Figur und Linie erhalten Methoden und Instanzvariablen die sie an Rechteck weitervererbenUneindeutigkeit wegen doppelter Methodennamen und Instanzvariablen (Skalieren())
Lösungsansatz: Echte Mehrfachvererbung vermeiden
Mehrfachvererbung nur mit Superklassen ohne Implementierungsteil (Java, C#)z.B. Java Interfaces:
f : Figur
virtual Flaeche()
r : Rechteck
Flaeche()
g : GUIObjekt
int farbtiefe
l : Linie
Int[][] Koordinaten
virtual Skalieren()
Zeichne()
virtual Zeichne()
virtual Skalieren()
public class Rechteck implements Figur, Linie { [...]} RealisierungParallelpfad
2. Übersetzung // Parametrisierung 20 / 30
Übersetzung von Parametrisierung
Ursprung in funktionaler Sprache MLViel Gesprächsstoff bzgl. Umsetzung von Parametrisierung in objektorientierten SprachenIn C++, Java und C# nachträglich hinzugefügt
Unterschiedliche StrategienC++ TemplatesJava Generics (ab J2SE 5.0)C# Generische Klassen (ab .NET 2.0)
“Correction these early oversights in C++ was a long and painful process, creating years of havoc as compilers never quite supported the same language, books never quite gave accurate information, trainers never quite taught the right stuff, and programmers never quite knew what to think“
(Betrand Mayer 1998, Entwickler der Programmiersprache Eiffel)
2. Übersetzung // Parametrisierung 21 / 30
Parametrisierung in C++ (1)
Generische Klassen: C++ TemplatesÜbersetzer expandiert Templates anhand aktueller ParameterFür jeden aktuellen Parameter eigene KlasseDaher: Kopierende (auch heterogene) Übersetzung
Stack<T>
void push(T item)
T pop() Stack<float>
void push(float item)
float pop()
Stack<int>
void push(int item)
int pop()
2. Übersetzung // Parametrisierung 22 / 30
Parametrisierung in C++ (2)
Umsetzung der Methodenaufrufe durch C++ Compiler Stack<int> intStackA;Stack<int> intStackB;intStackA.push(1);intStackB.push(2);
Stack<float> floatStack;floatStack.push(1);floatStack.pop();
_ZN5StackIiE4pushEi
_ZN5StackIfE4pushEf _ZN5StackIfE3popEv
2. Übersetzung // Parametrisierung 23 / 30
StrategieDem Übersetzungsprozess vorgeschaltete ExpansionVgl. mit Makro-Expansion durch Präprozessor in C
BewertungPerformanz Laufzeit: Parametrisierung bringt keinen Overhead mit sich – da Abbildung auf bekannte SprachkonstrukteKeine Integration in den Sprachkern – generische Klassen sind nicht Bestandteil des TypsystemsProgrammgröße wächst stark an (Redundanter Code)
Parametrisierung in C++ (3)
2. Übersetzung // Parametrisierung 24 / 30
Parametrisierung in Java (1)
Java GenericsHervorgegangen aus Pizza-Projekt (später GJ-Projekt)Anforderung: Auf unveränderter JVM lauffähigSeit J2SE 5.0 offizieller Bestandteil
ErasureJava-Compiler überprüft Typen (aktuelle Parameter)Formale Parameter werden durch ihren Bound ersetzt und Typkonvertierungen eingefügtErgebnis: Raw Type, frei von generischen InstuktionenAuch: Homogene Übersetzung
Bound (Obere Grenze):Implizit Object: class Stack<T> {...}Explizit Number: class Stack<T extends Number> {...}
2. Übersetzung // Parametrisierung 25 / 30
Parametrisierung in Java (2)
Beispiel Erasure Stack<T> mit Bound Object:
public class Stack<T> { public void push(T element){…} public T pop() {…}}
Stack<String> st = new Stack<String>();st.push("Hello World");String top = st.pop();
public class Stack { public void push(Object element){…} public Object pop() {…}}
Stack st = new Stack();st.push("Hello World");String top = (String) st.pop();
Generische Klasse: Raw Type (nach Erasure):
2. Übersetzung // Parametrisierung 26 / 30
Parametrisierung in Java (3)
Probleme (u.a.)
BewertungKeine Anpassungen an JVM nötig (Prämisse an Pizza-Projekt)Overhead durch TypkonvertierungenGenerische Typen existieren zur Laufzeit nicht mehr stack instanceof Stack<Integer> nicht möglichPrimitive Typen (int, float) können keine aktuellen Parameter sein, da kein gemeinsamer Bound existiert
Stack<String> strStack = new Stack<String>();strStack.push("Test");Object tmp = strStack;Stack<Integer> intStack = (Stack<Integer>) tmp; // Unchecked cast // without type[...]Integer intVal = intStack.pop(); // CastException // later in Code
2. Übersetzung // Parametrisierung 27 / 30
Parametrisierung in C# (1)
s1: Stack<string> s3 : Stack<object> s4 : Stack<int>
push()
pop()
...
string
push()
pop()
...
object
Code push()
Code pop()
Code push()
Code pop()
push()
pop()
...
intvtable Stack<string> vtable Stack<object> vtable Stack<int>
s2: Stack<string>
vtable Pointer
Instvar 1
...
Instvar n
vtable Pointer
Instvar 1
...
Instvar n
vtable Pointer
Instvar 1
...
Instvar n
vtable Pointer
Instvar 1
...
Instvar n
Kompatibilität generischer KlasseninstanzenDatenstrukturen und Algorithmen der aktuellen Parameter identisch
Referenztypen zueinander kompatibel (32-bit Pointer)Primitiven Datentypen untereinander und zu Referenzzypen inkompatibel
Kopie der virtuellen Methodentabelle für jede generische KlasseninstanzKompatible Klasseninstanzen verweisen auf gemeinsamen Code
2. Übersetzung // Parametrisierung 28 / 30
Parametrisierung in C# (2)
StrategieKombination der Vorteile der heterogenen Übersetzung (C++) und der homogenen Übersetzung (Java)Bauer, Höllerer: Echte generische Übersetzung
BewertungVöllständige Integration generischer Typen in den SprachkernTypüberprüfungen auch zur Laufzeit möglichWenig Overhead zur Laufzeit da Typkonvertierungen nicht nötigZusätzliche Verwaltung von vtables (Aber: Effiziente Implementation mit vtable Dictionaries möglich)
29 / 30
Gliederung
1. Objektorientierte Konzepte2. Übersetzung
1. Klassen und Methoden2. Vererbung3. Parametrisierung
3. Zusammenfassung & Fazit
3. Zusammenfassung & Fazit 30 / 30
Zusammenfassung & Fazit
Grundlagen objektorientierter SprachenKlassen und ObjekteMethoden und NachrichtenPolymorphie
ÜbersetzungAbstrakte MaschineKlassen und Methoden Gemeinsamkeiten mit imp. ProzedurenVererbung echte Mehrfachvererbung wird meist vermieden Strategien zur Realisierung von Parametrisierung
Hintergrund: Diskussionen um C++ Templates und Java Generic
Tieferes Verständnis für das objektorientierte Paradigma & für die Realisierung in konkreten objektorientierten Sprachen
Seminar Übersetzung von künstlichen Sprachen
Vielen Dank für Eure Aufmerksamkeit!
2. Übersetzung // Vererbung 32 / 30
Realisierung Mehrfachvererbung
f : Figur
virtual Flaeche()
r : Rechteck
Flaeche()
g : GUIObjekt
int farbtiefe
l : Linie
Int[][] Koordinaten
virtual Skalieren()
Zeichne()
virtual Zeichne()
virtual Skalieren()
GUIObjekt
Figur
GUIObjekt
Linie
Rechteck
a) Vererbungsgraph (Diamant)
GUIObjekt
Figur
Linie
Rechteck
Linie
FigurLinie
Rechteck
b.1) Mehrfache Instantiierung (von GUIObjekt)
b.2) Einfache Instantiierung (von GUIObjekt)
k : Kreis
Flaeche()
Zeichne()
Figur
Rechteck
Zurück
2. Übersetzung // Vererbung 33 / 30
Mehrfachvererbung
Beispiel:
Nachricht im Pfad: GUIObjekt <- Figur <- Rechteck Aufruf im Parallel-Pfad: GUIObjekt <- Linie <- Rechteck
Folgt Regeln der Polymorphie
Aber: Programmierer hätte erwarten können, dass GUIObjekt::Zeichne() aufgerufen wird (falls Pfad nicht offen liegt – Teamarbeit, Bibliothek)
f : Figur
virtual Flaeche()
r : Rechteck
Flaeche()
g : GUIObjekt
int farbtiefe
l : Linie
Int[][] Koordinaten
virtual Skalieren()
Zeichne()
virtual Zeichne()
virtual Skalieren()
Figur* f = new Rechteck();f->Zeichne(); // Linie::Zeichne() auf
Zurück