Seminar Übersetzung von künstlichen Sprachen Übersetzung objektorientierter Sprachen André Christ Münster, 5. Januar 2007
Jan 02, 2016
Seminar Übersetzung von künstlichen Sprachen
Übersetzung objektorientierter Sprachen
André ChristMünster, 5. Januar 2007
2 / 30
Gliederung
1. Objektorientierte Konzepte
2. Übersetzung1. Klassen und Methoden
2. Vererbung
3. Parametrisierung
3. Zusammenfassung & Fazit
1. Objektorientierte Konzepte 3 / 30
Objektorientierte Programmierung
Dr. Alan Kay: „Objektorientierte Programmierung“Austausch von Nachrichten zwischen Objekten
ObjekteZustand: Instanzvariablen
Verhalten: Methoden
Identität: Bei Erzeugung (Instanziierung) festgelegt (new)
NachrichtenAnfrage, eine Operation auf einem Objekt auszuführen
Zur Laufzeit wird „passende“ Methode ausgewählt und ausgeführt
Syntax 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 Methoden
Führt neuen Datentyp ein
MethodenMögliche Operationen eines Objekts
Vergleichbar mit Funktionen (Prozeduren) aus imperativen Sprachen
Aber: 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 annehmen
Prinzip nicht auf objektorientierte Sprachen beschränkt
Polymorphie insbesondere auch bei funktionalen Sprachen
KlassifikationSubklassen-Polymorphie
Parametrische-Polymorphie
Überladen
Coercion
Universelle-Polymorphie
Ad hoc-Polymorphie
Nach: Strachey / Cardelli, Wegner
1. Objektorientierte Konzepte 7 / 30
Subklassen-Polymorphie
Anwendungsfall: Plugins / Frameworks
Methoden-AuswahlregelEin Objekt einer Unterklasse B von A kann im Superklassenkontext von A verwendet werden
Methode m wird in Unterklasse überschrieben
Methode 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 Konzepte
2. Übersetzung1. Klassen und Methoden
2. Vererbung
3. 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-deskriptor
Klassen-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 Methodenrumpf
Framepointer: 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
Klassendeskriptor
Methodentabelle: 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 Funktionen
Funktionen müssen sich in ihrem Namen unterscheiden
Codierungsschema: _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 zugeordnet
Nach 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 Funktionstabelle
Sog. virtuelle Methoden in Unterklassen überschreibbar
Einträge in der vtable verweisen auf Methodenimplementationen
Sichten: 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 nachgeschlagen
Effiziente Implementation durch Funktionszeiger in C:
Standardisierte Indezierung der vtable
Umwandlung 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()Figur
RechteckQuadrat
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 weitervererben
Uneindeutigkeit 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 ML
Viel Gesprächsstoff bzgl. Umsetzung von Parametrisierung in objektorientierten Sprachen
In C++, Java und C# nachträglich hinzugefügt
Unterschiedliche StrategienC++ Templates
Java 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 Parameter
Für jeden aktuellen Parameter eigene Klasse
Daher: 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 Expansion
Vgl. mit Makro-Expansion durch Präprozessor in C
BewertungPerformanz Laufzeit: Parametrisierung bringt keinen Overhead mit sich – da Abbildung auf bekannte Sprachkonstrukte
Keine Integration in den Sprachkern – generische Klassen sind nicht Bestandteil des Typsystems
Programmgröß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 Typkonvertierungen
Generische Typen existieren zur Laufzeit nicht mehr stack instanceof Stack<Integer> nicht möglich
Primitive 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()
...
int
vtable 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 Klasseninstanz
Kompatible 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 Sprachkern
Typüberprüfungen auch zur Laufzeit möglich
Wenig Overhead zur Laufzeit da Typkonvertierungen nicht nötig
Zusätzliche Verwaltung von vtables (Aber: Effiziente Implementation mit vtable Dictionaries möglich)
29 / 30
Gliederung
1. Objektorientierte Konzepte
2. Übersetzung1. Klassen und Methoden
2. Vererbung
3. Parametrisierung
3. Zusammenfassung & Fazit
3. Zusammenfassung & Fazit 30 / 30
Zusammenfassung & Fazit
Grundlagen objektorientierter SprachenKlassen und Objekte
Methoden und Nachrichten
Polymorphie
ÜbersetzungAbstrakte Maschine
Klassen und Methoden Gemeinsamkeiten mit imp. Prozeduren
Vererbung echte Mehrfachvererbung wird meist vermieden
Strategien zur Realisierung von ParametrisierungHintergrund: Diskussionen um C++ Templates und Java Generic
Tieferes Verständnis für das objektorientierte Paradigma & für die Realisierung in konkreten objektorientierten Sprachen
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