Generative Programmierung

Ähnliche Dokumente
Einführung in die STL

Objektorientierte Programmierung mit C++ SS 2007

Einführung in die STL anhand eines ausgewählten Beispiels

C++ Templates - eine kleine Einführung. Allgemein. Funktionstemplates. Allgemein. Funktionstemplates. Klassentemplates

Teil V. Generics und Kollektionen in Java

Probeklausur: Programmierung WS04/05

Vorlesung Informatik 2

Ziel, Inhalt. Programmieren in C++ Wir lernen wie man Funktionen oder Klassen einmal schreibt, so dass sie für verschiedene Datentypen verwendbar sind

II.3.1 Rekursive Algorithmen - 1 -

1. Übung zu "Numerik partieller Differentialgleichungen"

Short Introduction to C# C# (C SHARP) Microsofts Antwort auf Java

Programmieren 3 C++ Prof. Peter Sommerlad Fredy Ulmer

Einführung in den Einsatz von Objekt-Orientierung mit C++ I

Einführung in die Nutzung der C++ - Standard - Bibliothek

Rekursive Funktionen

Objektorientierte Programmierung mit C++ Vector und List

1 Polymorphie (Vielgestaltigkeit)

Grundlagen der Programmierung Prof. H. Mössenböck. 6. Methoden

Proseminar: C# und.net. 6. Vortag Generische Klassen. Sebastian Wolf

Interaktionen zwischen Objekten durch Senden von Nachrichten und Reagieren auf empfangene Nachrichten

Theorie zu Übung 8 Implementierung in Java

Übung 13: Priority Queues (Vorrangwarteschlangen 1 )

Kapitel 8. Programmierkurs. Methoden. 8.1 Methoden

Methoden. von Objekten definiert werden, Methoden,, Zugriffsmethoden und Read-Only

Type Erasure in Java 5. Helmi Jouini Institut für Theoretische Informatik Universität Karlsruhe

Einführung in die Programmierung Wintersemester 2011/12

Die Programmiersprache C Eine Einführung

1. Typen und Literale (6 Punkte) 2. Zuweisungen (6 = Punkte)

Einführung Datentypen Verzweigung Schleifen. Java Crashkurs. Kim-Manuel Klein May 4, 2015

6 Speicherorganisation

Assoziative Container in C++ Christian Poulter

Einstieg in die Informatik mit Java

Stapel (Stack, Keller)

Einführung Datentypen Verzweigung Schleifen Funktionen Dynamische Datenstrukturen. Java Crashkurs. Kim-Manuel Klein

Probeklausur: Programmierung WS04/05

Javakurs für Anfänger

Programmierkurs. SoSe Markus Geveler Inst. f. Applied Mathematics, TU Dortmund.

Java 8. Elmar Fuchs Grundlagen Programmierung. 1. Ausgabe, Oktober 2014 JAV8

C++ - Eine Ubersicht fur Java-Programmierer

Programmieren I. Kapitel 5. Kontrollfluss

(allgemeine) OOP in C++ Klassen und header-files Konstruktorn / Destruktoren Speicherverwaltung C++ Standard Library / SLT

Programmierung in C/C++

DAP2-Programmierpraktikum Einführung in C++ (Teil 1)

Generische Datenstrukturen

Angewandte Mathematik und Programmierung

To know recursion, you must first know recursion. Borchers: Programmierung für Alle (Java), WS 06/07 Kapitel 17 1

Java Einführung Collections

7. Schnittstellen Grundlagen zu Schnittstellen. 7. Schnittstellen

Einführung in die Programmierung

12. Rekursion Grundlagen der Programmierung 1 (Java)

Javakurs für Anfänger

Benutzerdefinierte und zusammengesetzte Datentypen

Objektorientierte Programmierung

Systemnahe Programmierung in C/C++

Formale Spezialisierungstechniken. am Beispiel des binären Baums. Hybride Programmiersprachen Daniel Krompass Berlin, 2009

Nachname: Vorname: Matr.-Nr.: Punkte: 1. Aufgabe: ( / 25 Pkt.) Gegeben ist das folgende Struktogramm zur Berechnung von sin(x) mit Hilfe einer Reihe.

5. Tutorium zu Programmieren

Methoden (fortgeschritten) in C# - 1

Speicher und Adressraum

Klausurvorbereitung Lösung

Es ist für die Lösung der Programmieraufgabe nicht nötig, den mathematischen Hintergrund zu verstehen, es kann aber beim Verständnis helfen.

13 Java 4 - Entwurfsmuster am Beispiel des Rucksackproblems

Aufgabenblatt Nr. 5 Generizität und TicTacToe

Algorithmen und Programmierung II

JAVA für Nichtinformatiker - Probeklausur -

Silke Trißl, Prof. Ulf Leser Wissensmanagement in der Bioinformatik. Jede Applikation braucht eine Klasse mit einer main-methode

OOP und Angewandte Mathematik. Eine Einführung in die Anwendung objektorientierter Konzepte in der angewandten Mathematik

Klausur zu Objektorientierter Softwareentwicklung in C++ 4. Februar 2003 (WS 2002/2003) Beispiellösung

Aspekt-Orientierte Programmierung mit C++

Programmieren - C++ Funktions-Templates

Typdeklarationen. Es gibt in Haskell bereits primitive Typen:

Hochschule München, FK 03 SS Masterstudiengang Technische Berechnung und Simulation. Programmierung von CAx-Systemen Teil 1

6. Iteration (Schleifenanweisungen)

Vorlesung Programmieren

II. Grundlagen der Programmierung. 9. Datenstrukturen. Daten zusammenfassen. In Java (Forts.): In Java:

Pass by Value Pass by Reference Defaults, Overloading, variable Parameteranzahl

Programmiersprache 1 (C++) Prof. Dr. Stefan Enderle NTA Isny

Verwendung von Klassen in C++

Ein erstes Java-Programm

Übung HP Beispielaufgaben 3

12. Vererbung. Prof. Dr. Markus Gross Informatik I für D-ITET (WS 03/04)

Invarianten und sichere Vererbung

Javakurs FSS Lehrstuhl Stuckenschmidt. Tag 3 - Objektorientierung

Enumerations und innere Klassen

2. Semester, 2. Prüfung, Lösung

Objektorientierung Grundlagen

13. Vererbung. Prof. Dr. François E. Cellier Informatik I für D-ITET (HS 2012)

Programmieren I. Strategie zum Entwurf von Klassen. Beispiele. Design von Klassen. Dr. Klaus Höppner. Beispiel: Bibliothek

Klausur in Programmieren

Einstieg in die Informatik mit Java

Transkript:

Generative Programmierung Andreas Zeller Lehrstuhl für Softwaretechnik Universität des Saarlandes, Saarbrücken 2005-01-12 Grundidee: Parametrisierung Die Abstraktion ist ein Grundprinzip der Softwaretechnik. Seit Beginn der Programmierung wurden Konzepte entwickelt, um mit einem Programm möglichst viele ähnliche Aufgaben lösen zu können. Durch Instanziieren geeigneter Parameter kann ein Programm (eine Funktion, ein Modul ) auf verschiedenen Daten arbeiten. Daten sind klassische Parameter! Parametrisierte Datentypen Nicht nur Daten, sondern auch Datentypen können als Parameter benutzt werden. Grundidee: Bestandteile des Typs sind variabel z.b. der Objekttyp bei Containern. Geht explizit nur in manchen Sprachen: Ada generische Pakete C++ Templates Funktionale Sprachen Polymorphismus Generische Stacks in Java 5 Java 5 führt generische Klassen ein. 1

public class Stack<E> { // Instanzvariablen und Klassenkonstanten static final int size = 500; E s[] = new E[size]; int c = -1; // Öffentliche Funktionen public void empty() { c = -1; public void push(e x) { s[++c] = x; public void pop() { --c; public E top() { return s[c]; public boolean isempty() { return c == -1; Generische Stacks in Java 5 (2) Verwendung des Stacks: Stack<int> values = new Stack<int>(); values.push(42); Stack<String> pizza = new Stack<String>(); pizza.push("salami"); pizza.push("käse"); pizza.push("knoblauch"); pizza.push("knoblauch"); pizza.push("knoblauch"); Vorteil: Allgemeinheit, viel bessere Wiederverwendbarkeit Analog für generische abstrakte Objekte. Generische Stacks in Java 4 In Java 4 gab es noch keine generischen Datentypen. Alternative: eine allgemeine Oberklasse - z.b. Object: 2

public class Stack { // Instanzvariablen und Klassenkonstanten static final int size = 500; Object s[] = new Object[size]; int c = -1; // Öffentliche Funktionen public void empty() { c = -1; public void push(object x) { s[++c] = x; public void pop() { --c; public Object top() { return s[c]; public boolean isempty() { return c == -1; Generische Stacks in Java 4 (2) Nachteil: keine Typsicherheit Explizite Typumwandlung nötig Mögliche Laufzeit-Fehler bei Typumwandlung: Stack s = new Stack(); s.push("hugo"); string st = (string) s.top(); // OK int x = (int)s.top(); // Laufzeitfehler lässt sich problemlos übersetzen, führt aber zu einem Laufzeitfehler. Bei echten generischen Datentypen würde dies zur Übersetzungszeit erkannt! Templates in C++ Die Programmiersprache mit den weitestgehenden generischen Möglichkeiten ist C++. template<class T> class Vector { // Template public: explicit Vector(size_t n); // Konstruktor T& operator[] (size_t); // Feld-Zugriff Benutzung: Vector<int> is(100); is[10] = 15; Vector<double> ds(100); ds[20] = 3.0; 3

Template-Parameter Als Parameter für Templates sind Typnamen, Aufzählungen und Integers erlaubt: template<class T, int N> class Vector { private: T elems[n]; public: explicit Vector(); // Konstruktor T& operator[] (size_t); // Feld-Zugriff Benutzung: Vector<int, 100> is; is[10] = 15; Spezialisierung Oft ist es sinnvoll, die Implementierung eines Containers je nach Typ zu unterscheiden. template<class T> class Vector<bool> { // Vektor für Booleans template<class T> class Vector { // Standard-Vektor Spezialisierungs-Muster geben Typmuster an: template<class T> class Vector<T *> { // Vektor für Zeiger Standard-Container in C++ In C++ sind zahlreiche Container Bestandteil der Standard-Bibliothek (standard template library, STL) Sequenzen (vector, list, dequeue) Davon abgeleitet: stack, queue, Abbildungen (map, multimap) Davon abgeleitet: set, multiset, Teilweise spezialisiert für bestimmte Typen 4

Alle Container [] insert push_front push_back Iteration vector O(1) O(n)+ O(1)+ Ran list O(1) O(1) O(1) Bi dequeue O(1) O(n) O(1) O(1) Ran stack O(1) queue O(1) O(1) priority_queue O(log n) O(log n) map O(log n) O(log n)+ Bi multimap O(log n)+ Bi set O(log n)+ Bi multiset O(log n)+ Bi string O(1) O(n)+ O(n)+ O(1)+ Ran array O(1) Ran valarray O(1) Ran bitset O(1) Ran + bedeutet: von Zeit zu Zeit kommt Extra-Aufwand hinzu Sequenzen und Iteratoren Für Sequenzen können Iteratoren definiert werden: #include <iostream> #include <vector> using namespace std; int main() { vector<long> coll; coll.push_back(9); coll.push_back(6); // Eine Sammlung // 9 hinzufügen // 6 hinzufügen long sum; // Die Summe vector<long>::iterator itr; // Iterator definieren for (itr = coll.begin(); itr!= coll.end(); ++itr) sum += *itr; Container und Algorithmen Die STL stellt zahlreiche Algorithmen bereit, die auf Containern arbeiten. find gibt das erste passende Element zurück: vector<long>::iterator itr; itr = find(coll.begin(), coll.end(), 7); 5

find_if nimmt ein Prädikat: bool less_than_7(long v) { return v < 7;... itr = find_if(coll.begin(), coll.end(), less_than_7); Container und Algorithmen (2) for_each(b, E, F) ruft F() auf für alle Elemente von B bis E: void sum_up(long v) { sum += v;... for_each (coll.begin(), coll.end(), sum_up); Insgesamt sind mehr als 70 Algorithmen verfügbar zum Suchen, Kopieren, Zählen, Sortieren, Funktionsobjekte In den vorangegangenen Beispielen mußten wir die Funktionen und Prädikate (less_than_7, sum_up) jeweils explizit definieren. Grund: C++ kennt keine anonymen Funktionen (λ). Ansatz: Entsprechende Funktionsobjekte definieren Funktionsobjekte (2) Wir definieren eine Klasse mit geeignetem ()-Operator: template<class T> class Sum { T res; public: Sum(T i = 0): res(i) { void operator() (T x) { res += x; T result() const { return res; Benutzung: Sum<long> s; for_each (coll.begin(), coll.end(), s); cout << "Summe: " << s.result() << endl; 6

Funktionsobjekte (3) Die STL stellt passende Funktionsobjekte zur Verfügung: template <class Arg1, class Arg2, class Res> struct binary_function { typedef Arg1 first_argument_type; typedef Arg2 second_argument_type; typedef Res result_type; template <class T> struct less: public binary_function<t, T, bool> { bool operator() (const T& x, const T& y) const { return x < y; Anwendung: less<int>(x, y) ist äquivalent zu x < y Adapter In der Praxis benötigen wir häufig Funktionsobjekte, deren Argumente teilweise gebunden sind wie etwa less_than: template <class T> class less_than { T arg2; public: explicit less_than(const T& x): arg2(x) { bool operator() (const T& x) const { return less<t>(x, arg2); //... itr = find_if(coll.begin(), coll.end(), less_than<int>(7)); Adapter (2) Mit Adaptern lassen sich Funktionen auf spezialisiertere Funktionen abbilden ( Currying ). 7

Beispiel: f sei binäre Funktion bind2nd(f, y) ruft f mit y als zweitem Parameter auf bind1st(f, x) ruft f mit x als erstem Parameter auf bind2nd(less<int>(), 7)(x) ist äquivalent zu x < 7. bind2nd(less<int>(), 7)(4) ist true. Weitere Adapter: mem_fun, ptr_fun, not1, Adapter (3) Beispiele für den Einsatz von Adaptern: // Erstes Element < 7 suchen binder2nd<less<int> > less_than_7 = bind2nd(less<int>(), 7); itr = find_if(coll.begin(), coll.end(), less_than_7); // Erstes Element == 3 suchen itr = find_if(coll.begin(), coll.end(), bind1st(equal_to<int>(), 3)); Halleluja! Templates: Vor- und Nachteile Abscheuliche Syntax + Erhöhte Wiederverwendung (Generizität) + Optimierungsmöglichkeiten (Spezialisierung) Metaprogrammierung Der C++-Compiler muß zur Laufzeit Templates instantiieren und entscheiden, welche Template-Alternative benutzt wird. Mit diesen beiden Eigenschaften lassen sich Berechnungen zur Übersetzungszeit durchführen. Vorteil: erhöhte Effizienz! 8

Fakultät dynamisch Wir betrachten diesen klassischen Fakultäts-Code: int factorial(int n) { if (n == 0) return 1; else return n * factorial(n - 1); //... cout << "7! = " << factorial(7) << endl; factorial(7) wird zur Laufzeit berechnet. Fakultät statisch template<int n> struct Factorial { enum { RET = Factorial<n - 1>::RET * n ; // Spezialisierung template<> struct Factorial<0> { enum { RET = 1 ; //... cout << "7! = " << Factorial<7>::RET << endl; factorial<7>::ret wird zur Übersetzungszeit berechnet! Fibonacci-Zahlen statisch 9

template<int n> struct Fib { enum { RET = Fib<n - 1>::RET + Fib<n - 2>::RET ; template<> struct Fib<0> { enum { RET = 0; template<> struct Fib<1> { enum { RET = 1; //... cout << "fib(10) = " << Fib<10>::RET << endl; wird ebenfalls zur Übersetzungszeit berechnet Bedingungen template<bool cond, class Then, class Else> struct IF { typedef Then RET; // Spezialisierung für false template<class Then, class Else> struct IF<false, Then, Else> { typedef Else RET; //... IF<(1 + 2 > 4), short, int>::ret i; //... const bool have_ssl = true; typedef IF<have_ssl, SSLApache, StdApache>::RET Apache; Schleifen Wir betrachten eine iterative Implementierung zum Berechnen von Fibonacci-Zahlen: 10

int fib(int n) // n > 0 { int i = 1, x = 1, y = 0; while (i < n) { i = i + 1; int x_ = x; x = x + y; y = x_; return x; Kann man das so auch zur Übersetzungszeit berechnen? Schleifen (2) Wir definieren eine Anweisung und eine Bedingung für die Berechnung von Fibonacci-Zahlen: template<int i_, int x_, int y_> struct FibStat { enum { i = i_, x = x_, y = y_ ; typedef FibStat<i + 1, x + y, x> Next; template<int n> struct FibCond { template<class Statement> struct Code { enum { RET = Statement::i < n ; Schleifen (3) Hiermit können wir eine Schleife füllen: template<int n> struct Fib { enum { RET = WHILE<FibCond<n>, FibStat<1, 1, 0> >::RET::x ;... cout << "fib(8) = " << Fib<8>::RET << endl; Schleifen (4) WHILE ist mit Hilfe von IF definiert: 11

template<class Statement> struct STOP { typedef Statement RET; template<class Condition, class Statement> struct WHILE { typedef typename IF<Condition::template Code<Statement>::RET, WHILE<Condition, typename Statement::Next>, STOP<Statement> >::RET::RET RET; Erkenntnis: Der C++-Compiler ist Turing-universell! Anwendungen Auswahl von Alternativen zur Übersetzungszeit Bestimmung von Werten zur Übersetzungszeit Gesteuerte Optimierungen (z.b. Loop unrolling) Konzepte Generische Programmierung nutzt Parametrisierung, um zur Übersetzungszeit neue Typen zu generieren Templates in C++ ermöglichen erhöhte Wiederverwendung furch Generizität Optimierungsmöglichkeiten für bestimmte Typen und Werte (Spezialisierung) C++-Templates ermöglichen Metaprogrammierung: Auswahl von Alternativen zur Übersetzungszeit Bestimmen von Werten und Typen zur Übersetzungszeit Literatur Musser et al., STL Tutorial and Reference Guide Alles über die STL. Stroustrup, The C++ Programming Language Alles über C++. Czarnecki + Eisenecker, Generative Programming (Kapitel 10). Metaprogramming 12