Generative Programmierung

Ähnliche Dokumente
Einführung in die STL

Objektorientierte Programmierung mit C++ SS 2007

Teil V. Generics und Kollektionen in Java

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

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

Probeklausur: Programmierung WS04/05

Vorlesung Informatik 2

II.3.1 Rekursive Algorithmen - 1 -

Rekursive Funktionen

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 die Nutzung der C++ - Standard - Bibliothek

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

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

Objektorientierte Programmierung mit C++ Vector und List

1 Polymorphie (Vielgestaltigkeit)

Theorie zu Übung 8 Implementierung in Java

Die Programmiersprache C Eine Einführung

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

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

Einführung in die Programmierung Wintersemester 2011/12

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

Kapitel 8. Programmierkurs. Methoden. 8.1 Methoden

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

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

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

Übung 13: Priority Queues (Vorrangwarteschlangen 1 )

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

Programmieren I. Kapitel 5. Kontrollfluss

Javakurs für Anfänger

Stapel (Stack, Keller)

6 Speicherorganisation

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

Einstieg in die Informatik mit Java

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

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

Programmierung in C/C++

Probeklausur: Programmierung WS04/05

C++ - Eine Ubersicht fur Java-Programmierer

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

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

Javakurs für Anfänger

Generische Datenstrukturen

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

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

Angewandte Mathematik und Programmierung

Assoziative Container in C++ Christian Poulter

Java Einführung Collections

12. Rekursion Grundlagen der Programmierung 1 (Java)

Einführung in die Programmierung

Objektorientierte Programmierung

Benutzerdefinierte und zusammengesetzte Datentypen

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

Systemnahe Programmierung in C/C++

7. Schnittstellen Grundlagen zu Schnittstellen. 7. Schnittstellen

Methoden (fortgeschritten) in C# - 1

Vorlesung Programmieren

5. Tutorium zu Programmieren

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

Speicher und Adressraum

Klausurvorbereitung Lösung

Aspekt-Orientierte Programmierung mit C++

JAVA für Nichtinformatiker - Probeklausur -

Algorithmen und Programmierung II

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

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

Typdeklarationen. Es gibt in Haskell bereits primitive Typen:

zu große Programme (Bildschirmseite!) zerlegen in (weitgehend) unabhängige Einheiten: Unterprogramme

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

Programmieren - C++ Funktions-Templates

6. Iteration (Schleifenanweisungen)

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

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

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

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

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

JAVA - Methoden

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

zu große Programme (Bildschirmseite!) zerlegen in (weitgehend) unabhängige Einheiten: Unterprogramme

Ein erstes Java-Programm

4. Komponentenarten. Java-Beispiele:

Invarianten und sichere Vererbung

Verwendung von Klassen in C++

Übung HP Beispielaufgaben 3

Aufgabenblatt Nr. 5 Generizität und TicTacToe

Einstieg in die Informatik mit Java

Objektorientierung Grundlagen

Enumerations und innere Klassen

Advanced Programming in C

Transkript:

1/100 Generative Programmierung Andreas Zeller Lehrstuhl Softwaretechnik Universität des Saarlandes, Saarbrücken

Grundidee: Parametrisierung 2/100 Die Abstraktion ist ein weiteres 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 Instantiieren geeigneter Parameter kann ein Programm (eine Funktion, ein Modul... ) auf verschiedenen Daten arbeiten. Daten sind klassische Parameter!

Parametrisierte Datentypen 3/100 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 Pizza 4/100 Pizza ist ein Java-Dialekt mit generischen Klassen. 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 Pizza (2) 5/100 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 6/100 In 100% reinem Java gibt es keine generischen Datentypen. Alternative: eine allgemeine Oberklasse - z.b. Object: 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 (2) 7/100 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äßt sich problemlos übersetzen, führt aber zu einem Laufzeitfehler. Bei echten generischen Datentypen würde dies zur Übersetzungszeit erkannt!

Templates in C++ 8/100 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;

Template-Parameter 9/100 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 10/100 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++ 11/100 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

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 12/100

Sequenzen und Iteratoren 13/100 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 14/100 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);

Container und Algorithmen 14/100 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); 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) 15/100 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 16/100 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) 17/100 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;

Funktionsobjekte (3) 18/100 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 19/100 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) 20/100 Mit Adaptern lassen sich Funktionen auf spezialisiertere Funktionen abbilden ( Currying ). 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) 21/100 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);

Adapter (3) 21/100 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); Halleluja! // Erstes Element == 3 suchen itr = find_if(coll.begin(), coll.end(), bind1st(equal_to<int>(), 3));

Templates: Vor- und Nachteile 22/100 Abscheuliche Syntax

Templates: Vor- und Nachteile 22/100 Abscheuliche Syntax + Erhöhte Wiederverwendung (Generizität)

Templates: Vor- und Nachteile 22/100 Abscheuliche Syntax + Erhöhte Wiederverwendung (Generizität) + Optimierungsmöglichkeiten (Spezialisierung)

Metaprogrammierung 23/100 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.

Fakultät dynamisch 24/100 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 25/100 template<int n> struct Factorial { enum { RET = Factorial<n - 1>::RET * n ; // Spezialisierung template<> struct Factorial<0> { enum { RET = 0 ;

Fakultät statisch 25/100 template<int n> struct Factorial { enum { RET = Factorial<n - 1>::RET * n ; // Spezialisierung template<> struct Factorial<0> { enum { RET = 0 ; //... cout << "7! = " << factorial<7>::ret << endl; factorial<7>::ret wird zur Übersetzungszeit berechnet!

Fibonacci-Zahlen statisch 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; 26/100

Fibonacci-Zahlen statisch 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 26/100

Bedingungen 27/100 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;

Bedingungen 27/100 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;

Bedingungen 27/100 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;

Bedingungen 27/100 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 28/100 Wir betrachten eine iterative Implementierung zum Berechnen von Fibonacci-Zahlen: 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) 29/100 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) 30/100 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) 31/100 WHILE ist mit Hilfe von IF definiert: 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 32/100 Auswahl von Alternativen zur Übersetzungszeit Bestimmung von Werten zur Übersetzungszeit Gesteuerte Optimierungen (z.b. Loop unrolling)

Zusammenfassung 33/100 Generische Programmierung nutzt Parametrisierung, um zur Übersetzungszeit neue Typen zu generieren

Zusammenfassung 33/100 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)

Zusammenfassung 33/100 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 34/100 http://www.research.avayalabs.com/user/wadler/pizza/ Alles über Pizza Musser et al., STL Tutorial and Reference Guide Alles über die STL. Stroustrup, The C++ Programming Language Alles über C++. Czarnecki + Eisenecker, Generative Programming Metaprogramming (Kapitel 10).