Vorlesung „Programmieren“ Programmierparadigmen Prof. Dr. Stefan Fischer Institut für Telematik, Universität zu Lübeck http://www.itm.uni-luebeck.de/people/fischer Programmiersprachen-Paradigmen • Eine Programmiersprache dient dem Aufschreiben von Algorithmen – Ein Compiler übersetzt in Maschinensprache • Die Art und Weise des „Aufschreibens“ unterscheidet sich je nach Programmiersprache sehr deutlich – Verschiedene Paradigmen existieren – Bisher: Imperative Programmierung Security - 04 Cryptology #2 Unterschiedliche Sprachenkonzepte • Imperative Programmiersprachen – Grundprinzip: Folge von Variablenzuweisungen – Wesentlich: Prozedurale Programmierung – Beispiele: Algol, Fortran, Cobol, Pascal, C, Basic – Spezialfall: Objektorientierte Programmierung • Grundprinzip: Interaktionen zwischen „Objekten“ • Beispiele: SmallTalk, Java, C++ • Funktionale Programmiersprachen – Grundprinzip: Term-Ersetzung – Beispiele: Lisp, HOPE, Miranda, SML, Haskell • Logikbasierte Programmiersprachen – Grundprinzip: Prädikatenlogik – Beispiel: Prolog 5-3 Motivation Security - 04 Cryptology #4 Beispiel: Mehrmals Leerzeichen zählen • Aufgabe: Zähle Leerzeichen in beiden folgenden Sätzen und gebe beides aus – „Man muss die Welt nicht verstehen, man muss sich nur darin zurechtfinden. (Albert Einstein)“ – „Die besten Dinge im Leben sind nicht die, die man für Geld bekommt.(Albert Einstein)“ Security - 04 Cryptology #5 Mögliches Programm public class Zeichenzaehlen { public static void main(String[] args){ char text[] = "Man muss […] darin zurechtfinden. (Albert Einstein)".toCharArray(); int anzahlLeerzeichen = 0; for(int aktuellesZeichen = 0; aktuellesZeichen < text.length; aktuellesZeichen++) { if( text[aktuellesZeichen] == ' ' ) { anzahlLeerzeichen++; } } System.out.print(anzahlLeerzeichen); char text2[] = "Die besten Dinge […] Geld bekommt. (Albert Einstein)".toCharArray(); int anzahlLeerzeichen2 = 0; for(int aktuellesZeichen2 = 0; aktuellesZeichen2 < text2.length; aktuellesZeichen2++) { if( text2[aktuellesZeichen2] == ' ' ) { anzahlLeerzeichen2++; } } System.out.print(anzahlLeerzeichen2); } } Bildquelle: http://www.konsumer.info/?p=15528, Programm: 08-Programmierparadigmen\1-Zeichenzaehlen\Zeichenzaehlen.java Security - 04 Cryptology #6 Ausgabe des Programms • 2 x 13 Leerzeichen? • Kann das stimmen? • Zufällig gleich viele? • Haben wir einen Fehler gemacht beim Anpassen des Programms? Security - 04 Cryptology #7 Beliebter Fehler public class Zeichenzaehlen { public static void main(String[] args){ char text[] = "Man muss […] darin zurechtfinden. (Albert Einstein)".toCharArray(); int anzahlLeerzeichen = 0; for(int aktuellesZeichen = 0; aktuellesZeichen < text.length; aktuellesZeichen++) { if( text[aktuellesZeichen] == ' ' ) { anzahlLeerzeichen++; } } System.out.print(anzahlLeerzeichen); char text2[] = "Die besten Dinge […] Geld bekommt. (Albert Einstein)".toCharArray(); int anzahlLeerzeichen2 = 0; } for(int aktuellesZeichen2 = 0; aktuellesZeichen2 < text2.length; aktuellesZeichen2++) { if( text[aktuellesZeichen2] == ' ' ) { anzahlLeerzeichen2++; } } System.out.print(anzahlLeerzeichen); Copy/Paste-Fehler } Bildquelle: http://www.konsumer.info/?p=15528, Programm: 08-Programmierparadigmen\1-Zeichenzaehlen\Zeichenzaehlen.java Security - 04 Cryptology #8 Motivation • Bisher möglich: Lange Abfolge von Code • Probleme – – – – – Lesbarkeit Fehleranfälligkeit Viel Copy & Paste Keine zentrale Fehlerbehebung Große Programme nicht wartbar Betriebssystem Codezeilen Windows NT 3.1 4-5 Mio. Windows NT 4.0 11-12 Mio. Windows 2000 >29 Mio. Windows XP 45 Mio. Windows Server 2003 50 Mio. OpenSolaris 9.7 Mio. FreeBSD 8.8 Mio. Mac OS X 10.4 86 Mio. Linux Kernel 2.6.0 5.2 Mio. Linux Kernel 2.6.35 13.5 Mio. #9 Prozedurale Programmierung Prozedurale Programmierung • Zerlegung von Programmen in kleinere, wiederverwendbare Einheiten – sog. Prozeduren Monolithisches Programm • Vorteile – Kapselung einzelner Funktionalitäten – Bessere Wiederverwendbarkeit – Lesbarerer Code • „Was tut er?“ (z.B. Zeichen zählen) statt „Wie tut er es?“ (die ganzen Instruktionen) – Fehlerbehebung an einer Stelle #11 Prozedur (auch: Funktion) • Eingabeparameter – Übergabe von Werten an die Funktion – Definiert als Menge von Variablen mit bestimmtem Datentyp • Rückgabe Eingabewerte Prozedur / Funktion (Black Box) – Wert mit einem bestimmten Datentyp – Spezieller Datentyp für keine Rückgabe: void • Beispiele für Deklarationen (sog. Signatur) – – – – – Ausgabewert void main(String[] args); int zaehleLeerzeichen(char[] text); char[] rueckwaerts(char[] text); boolean istLeerzeichen(char zeichen); boolean istKontoGedeckt(int konto, int blz); #12 Signatur und Implementierung Signatur (auch: Deklaration) int zaehleLeerzeichen(char[] text) { // Hier steht die Implementierung der Funktion // (in einer Blockanweisung) } Implementierung (auch: Body oder Definition) #13 Signatur und Implementierung int zaehleLeerzeichen(char[] text) { int anzahlLeerzeichen = 0; for(int i = 0; i < text.length; ++i) if ( text[i] == ' ' ) anzahlLeerzeichen++; return anzahlLeerzeichen; } Rückgabe der Funktion (wichtig: Datentyp) #14 Exkurs: Blockanweisung • Blockanweisungen definieren einen eigenen „Scope“ (Bereich) • Beispiele – „class MeinProgramm“ – Prozedur „main“ Security - 04 Cryptology #15 Exkurs: Blockanweisung • Begrenzen „Sichtbarkeit“ bzw. „Lebensdauer“ von Elementen (z.B. Variablen) • Beispiele – Variable i (Zeile 3) „gehört“ zur Klasse „Blockanweisung“ (globale Variable) – Variable i (Z. 6) gehört zu „main“ (lokale Variable) – Variable i2 „lebt“ nur innerhalb der Blockanweisung (Z. 9-11) – Variable i3 von Z. 15-22 – Variable i4 in Z. 19 Security - 04 Cryptology #16 Implementierung einer Funktion • Wie eine „Erweiterung“ der Blockanweisung – Es gibt ein paar weitere „lokale“ Variablen – Stellen die Parameter einer Funktion dar • Parameter werden wie normale lokale Variablen verwendet werden – Werte der Parameter werden beim Aufruf festgelegt Security - 04 Cryptology #17 Aufruf von Funktionen • Aufruf über Namen (Identifier) der Funktion • Übergabe von Parametern an die Funktion – Richtige Anzahl – Richtiger Datentyp Security - 04 Cryptology #18 Ausgabe des Programms • Programm verhält sich identisch zu dem Copy & Paste-Programm – Es unterscheidet sich daher nicht im Ergebnis • Aber das Programm ist – – – – lesbarer, einfacher, wartbarer, wiederverwendbarer, ... Security - 04 Cryptology #19 Weiteres Beispiel: Inverter Security - 04 Cryptology #20 Mit Prozeduren • Zerlegen in einzelne Operationen – Zeichen lesen – Auf „Enter“ prüfen – Prüfen, ob noch Platz im Puffer ist – Invers ausgeben • Aufrufen im Hauptprogramm Security - 04 Cryptology #21 Prozedurale Programmierung • Zerlegen des Programms in Prozeduren / Funktionen – Wesentlich: Übergabe von Parametern an Funktionen • Programm besteht aus Sequenz von Funktionsaufrufen – Erste Funktion: main • Prozeduren können auch globale Variablen verändern – „Zustand“ über mehrere Aufrufe hinweg Security - 04 Cryptology #22 Beispiel: Bankkonto • Bankkonto hat einen Zustand... – Kontostand • ...und Operationen – Einzahlen, – Auszahlen, – Kontostand erfragen • Mögliche Implementierung? Security - 04 Cryptology #23 Problem: Vergessen der Zuweisung erzeugt falsche Semantik #24 Ausgabe des Programms #25 Etwas besser: Verwendung einer statischen Variable #26 Ausgabe des Programms #27 #28 Ausgabe des Programms #29 Probleme prozeduraler Programmierung • Bisher – Aufteilung des Programms in Prozeduren mit bestimmten Aufgaben – Hauptprogramm steuert Programmfluss über Funktionsaufrufe – Übergabe von Daten über Parameter oder globale Variablen • Probleme – Verwendung globaler Variablen ist problematisch – Ausführung einer Funktion abhängig vom Zustand (Inhalt) der globalen Variable – Man nennt dies auch „Seiteneffekt“ • Alternatives Konzept: Funktionale Programmierung Security - 04 Cryptology #30 Funktionale Programmierung Funktionale Programmierung • Inspiriert von mathematischen Funktionen • Wir besprechen hier nur die Grundidee • Funktionale Programmierung ist viel mehr • Es gibt auch „funktionale“ Programmiersprachen Security - 04 Cryptology #32 Funktionale Programmierung • Mathematische Funktionen sind wie eine große Tabelle • Abhängig von den Parametern, findet man das (immer konstante) Ergebnis in einer Tabelle • Wichtiges Prinzip: Termersetzung – f(2) – f(4) 4 16 Security - 04 Cryptology #33 Funktionale Programmierung • Vereinfacht dargestellt ist funktionale wie prozedural ohne globale Variablen • Denkweise ist sehr wichtig für gut testbare und wartbare Programme Security - 04 Cryptology #34 Zusammenfassung und Ausblick • Prozedurale und funktionale Programmierung hilft, Programme besser wartbar, fehlerfreier, etc. zu machen – Bringt keine weitere „Mächtigkeit“ der Programmiersprache – Mittel, um den Quelltext für Menschen besser verständlich zu machen • Prozedural: Aufteilen von Programmen in kleine, handliche Prozeduren – Dürfen auch globale Variablen verändern • Funktional: Wie prozedural, nur ohne globale Variablen #35