Folien

Werbung
Informatik 3
Sitzung 9 - Theorie
Roland Mühlenbernd
Einleitung: Überblick
Themen der 9. Session:
I Kapitel 7: Typen & Datenkonzepte
I Typen
I Reihungen
I Zeichenketten
I Verbunde & Mengen
I Einfache Typen
I Konstanten
I
Kapitel 8: Ablaufsteuerung & algorithmische Konzepte
I Routinen: Prozeduren & Funktionen
I Zusicherungen
I Anweisungen
7. Typen & Datenkonzepte:Gemeinsames
Gemeinsamkeiten der Typsysteme der 5 Sprachen
I
Typbindung:
Jede Variable, jeder Parameter, jeder Ausdruck besitzt
einen zur Kompilationszeit festgelegten, unveränderlichen
'statischen Typ'.
I
Klassen und Typen:
Das Klassenkonzept ist in das Typkonzept
integriert. Jede Klasse beschreibt einen Typ. (Eine generische
Klasse beschreibt eine Menge von Typen.)
I Es gibt sprachdenierte und programmiererdenierte Typen.
I
Statische Typprüfung:
Der Kompilierer prüft Typverträglichkeit in
Ausdrücken, bei Zuweisungen, Parameterübergaben usw.
I Bei numerischen Basistypen gibt es Regeln zur
Typanpassung
impliziten
I Gröÿen, die sich auf Objekte (Exemplare von Klassen) beziehen,
haben auch einen
I
Konformität:
dynamischen Typ.
Der dynamische Typ einer Objekt-Gröÿe muss einer
Unterklasse ihres statischen Typs entsprechen.
7. Typen & Datenkonzepte: Typsysteme
I
Component Pascal, C++:
Es gibt Typen, die nicht durch Klassen
beschrieben sind. Die Typ-Spezialisierungsstruktur ist typisch für hybride
Sprachen:
I sprachdenierte Typen (predened, built-in): einfache
Basistypen
I programmiererdenierte Typen: gewöhnliche Typen, Klassen
I
Eiel:
Jeder Typ ist durch eine Klasse beschrieben. Die
Typ-Spezialisierungsstruktur ist typisch für rein objektorientierte
Sprachen:
I sprachdenierte Klassen: Standardbibliotheksklassen,
Basisklassen
I programmiererdenierte Klassen
I
Java:
Bis auf primitive Typen ist jeder Typ durch eine Klasse beschrieben.
I sprachdenierte Typen: Standardbibliotheksklassen, primitive
Typen, Hüllenklassen
I programmiererdenierte Typen: Klassen
I
C#:
Jeder Typ kann durch eine Klasse
beschrieben werden.
class oder eine Struktur struct
7. Typen & Datenkonzepte: Sprachdenierte Typen
Sprachdenierte Typen mit Operatoren
7. Typen & Datenkonzepte: Sprachdenierte Typen
Sprachdenierte Typen mit Operatoren
7. Typen & Datenkonzepte: Sprachdenierte Typen
Sprachdenierte Typen mit Operatoren
7. Typen & Datenkonzepte: Sprachdenierte Typen
Sprachdenierte Typen mit Operatoren
7. Typen & Datenkonzepte: Sprachdenierte Typen
Sprachdenierte Typen mit Operatoren
decimal hat im Vergleich zu Gleitkommatypen höhere Genauigkeit und
kleineren Wertebereich.
7. Typen & Datenkonzepte: Sprachdenierte Typen
Sprachdenierte Typen mit Operatoren
7. Typen & Datenkonzepte: Programmiererdef. Typen
Programmiererdenierte Typen
7. Typen & Datenkonzepte: Programmiererdef. Typen
Operatoren programmiererdenierte Typen
I
Component Pascal:
Programmiererdenierte Typen sind Typen
zweiter Klasse: Operatoren sind nämlich für sie nicht durch den
Programmierer denierbar.
I
Eiel:
Operatoren sind syntaktische Varianten von Funktionen, die
in einer Klasse (re-)deniert werden. Operatoren können mit
beliebigen Sonderzeichen als Namen in Präx- und Inxschreibweise
deniert werden. Konsistente Semantik von Operatoren wird über
Abstraktionen und Vererbungsbeziehungen erreicht.
I
C++ nutzt vor allem den Mechanismus des Überladens.
Nur
Operatorsymbole, die schon in der Sprache deniert sind, können
gewählt werden. Operatoren können global oder an Klassen
gebunden sein.
I
Java:
Hier sind die nicht-Klassen Typen (primitive Typen,
Reihungen) Typen zweiter Klasse. Für Klassen-Typen werden
Operatoren als Funktionen in der Klasse deniert.
I
C#:
Ähnlich wie in Eiel für Klassen, wie auch für Strukturen.
7. Typen & Datenkonzepte: Typdeklaration & -denition
Typdeklarationen, Typdenitionen
I Component Pascal:
I Eine Typdeklaration führt einen neuen Typ mit neuem Namen
ein und hat die Form TYPE Typname = Typangabe. Beispiel:
TYPE
GraphObjekt* = POINTER TO ABSTRACT RECORD farbe*: INTEGER; END;
Punkt* = POINTER TO RECORD (GraphObjekt) x*, y*: INTEGER; END;
Linie* = POINTER TO RECORD (GraphObjekt) xStart*, yStart*, xEnde*, yEnde*:
INTEGER; END;
I Typangaben bilden eine syntaktische Einheit.
I
/
Die Namen sprachdenierter Typen können mit anderer
Bedeutung belegt werden.
I
Eiel
I Es gibt keine Typdenitionen im Sinne von Component Pascal
oder C++.
I Jede Klasse erhält in ihrer Deklaration einen Namen.
7. Typen & Datenkonzepte: Typdeklaration & -denition
Typdeklarationen, Typdenitionen
I C++
I Eine Typdenition gibt einem Typ einen neuen Namen, sie
führt aber keinen neuen Typ ein und hat näherungsweise die
Form
typedef Typangabe-Teil1 Typname Typangabe-Teil2;
I Beispiele:
typedef unsigned int uint;
typedef struct { double re, double im; } complx;
I
Java
I Typen werden über den Namen einer Klassen deklariert:
class Typname {...Felder, Methoden... }
I
C#
I Typen werden über den Namen eines Namensraumes, einer
Klassen oder einer Struktur deklariert:
namespace Typname {... }, class Typname {... }, struct
Typname {... }
7. Typen & Datenkonzepte: Wertprüfung zur Laufzeit
Wertprüfung zur Laufzeit
Bei allen fünf Sprachen ist Unter- und Überlauf von Wertebereichen
zur Laufzeit i.A. möglich. Alle Sprachen bis auf C++ prüfen die
Einhaltung von Wertebereichen zur Laufzeit, d.h. nur C++ ist in
dieser Hinsicht nicht typsicher.
7. Typen & Datenkonzepte: Implizite Typanpassung
Implizite Typanpassung
I
I
Component Pascal: Numerische Typen werden in
arithmetischen Ausdrücken, bei Zuweisungen und
Parameterübergaben implizit vom kleineren zum gröÿeren Typ
angepasst, sodass keine Information, höchstens Genauigkeit
verlorengeht. Die Kompatibilitätsregeln beruhen auf dem
Typeinschluss: BYTE ⊆ SHORTINT ⊆ INTEGER ⊆
LONGINT ⊆ SHORTREAL ⊆ REAL
Der Kompilierer prüft Typkompatibilität.
Eiel: Numerische Typen werden in arithmetischen
Ausdrücken, bei Zuweisungen und Parameterübergaben
implizit vom leichteren zum schwereren Typ angepasst, sodass
keine Information, höchstens Genauigkeit verlorengeht. Die
Konformitätsregeln beruhen auf der Balancierungsregel
INTEGER ⊆ REAL ⊆ DOUBLE
Der Kompilierer prüft Typkonformität.
7. Typen & Datenkonzepte: Implizite Typanpassung
Implizite Typanpassung
I
I
C++: Alle Fundamentaltypen können in Ausdrücken, bei
Zuweisungen und Parameterübergaben beliebig eingesetzt
werden, sie werden implizit in den geforderten Typ ohne
Rücksicht auf Verlust an Genauigkeit oder Information
konvertiert. Es gibt daher weder Kompatibilitätsprüfungen des
Kompilierers noch Laufzeitprüfungen.
Java, C#: Wie bei Component Pascal und Eiel wird implizit
verlustlos vom kleineren zum gröÿeren Typ angepasst.
7. Typen & Datenkonzepte: Explizite Typanpassung
Explizite Typanpassung
I
Component Pascal, Eiel:
Es gibt kein Sprachkonstrukt zur
Konversion programmiererdenierter Typen oder Klassen. Der
Programmierer kann natürlich selbst Konversionsfunktionen
schreiben, wenn solche benötigt werden.
I
Component Pascal:
Zur expliziten Typanpassung bestimmter
Basistypen gibt es die sprachdenierten Funktionen CHR(x) (INT to
CHAR), ENTIER(x) (REAL to INT), LONG(x) (to the next 'longer'
type), ORD (CHAR to INT), SHORT (to the next 'shorter' type).
I
Eiel:
Die Bibliotheksklasse BASIC_ROUTINES enthält für
Basisklassen die Konversionsfunktionen charcode, charconv,
double_to_integer, double_to_real, real_to_integer.
I
C++:
Die aus C übernommene Typecast-Notation zur
Typkonversion kann auf beliebige Typen, also auch auf Klassen
angewandt werden:
Some_type * obj_some = (Some_type*) obj;
((Some_type *) obj)-> feature_of_Some_type
7. Typen & Datenkonzepte: Explizite Typanpassung
Explizite Typanpassung
I Java: Es gibt mehrere Arten, hier eine kleine Auswahl:
I
Widening Primitive Conversion für primitive Typen (kein
Informationsverlust):
I byte to short, int, long, oat, or double
I short to int, long, oat, or double
I char to int, long, oat, or double
I int to long, oat, or double
I long to oat or double
I oat to double
I Beispiel: int num = 1; oat real = (oat)num;
I
Narrowing Primitive Conversion für primitive Typen (mit
Informationsverlust):
I short to byte or char
I char to byte or short
I int to byte, short, or char
I long to byte, short, char, or int
I oat to byte, short, char, int, or long
I double to byte, short, char, int, long, or oat
I Beispiel: oat approx = 1.3; int value = (int)approx;
7. Typen & Datenkonzepte: Explizite Typanpassung
Explizite Typanpassung
I Java: Es gibt mehrere Arten, hier eine kleine Auswahl:
I
I
I
Boxing Conversion von primitive Typen zu Hüllenklassen.
Beispiel: r.intValue() == p weiÿt Variable r von Typ Integer
den Wert der Variable p vom Typ int zu.
Unboxing Conversion von Hüllenklassen zu primitive Typen.
Beispiel: r.intValue() konvertiert Variable r von Typ Integer in
Typ int.
C#: Explizite Typanpassung durch casts wie in C++ oder
durch Helferklassen, zum Beispiel System.Convert oder
Int32.Parse
7. Typen & Datenkonzepte: Statischer & Dynamischer Typ
I
I
I
I
Eine Unterscheidung zwischen statischem und dynamischem
Typ ist nur in Zusammenhang mit Vererbung relevant.
Der statische Typ einer Gröÿe ist der Typ, mit dem sie (zur
Kompilationszeit) vereinbart ist.
Der dynamische Typ einer Gröÿe ist der Typ ihres Werts zur
Laufzeit.
Der dynamische Typ entscheidet, welche Version einer
gerufenen Operation ausgeführt wird
7. Typen & Datenkonzepte: Statischer & Dynamischer Typ
I
I
I
I
I
Component Pascal: Bei einer Zeigervariablen oder einem
Referenzparameter eines Verbundtyps kann der dynamische
Typ eine Erweiterung des statischen Typs sein.
Eiel: Bei Gröÿen mit Referenzsemantik kann der dynamische
Typ eine Erweiterung des statischen Typs sein.
C++: Im Unterschied zu Component Pascal und Eiel besitzt
die Gröÿe in C++ nicht einen dynamischen Typ, sondern wird
vom statischen Typ in diesen konvertiert.
Java: nur Referenzsemantik, wie Eiel
C#: wie in C++
7. Typen & Datenkonzepte: Typinformation zur Laufzeit
Typinformation zur Laufzeit
I
Component Pascal:
Es gibt das Konstrukt Typtest.
IF obj IS SomeType THEN
...
ELSIF obj IS OtherType THEN
...
END
I
Eiel:
Viele Probleme lassen sich mit dem Mechanismus verankerter
Typen (
anchored types) und der Kovarianzregel ohne Typtests lösen. Die
ANY und damit jede Klasse enthält das Merkmal
gemeinsame Oberklasse
generator : STRING, das den Klassennamen als Zeichenkette liefert:
if obj.generator.is_equal(SOME_TYPE) then
...
elseif obj.generator.is_equal(OTHER_TYPE) then
...
end
Den Typvergleich zweier Objekte erlaubt das in
ANY denierte Merkmal
conforms_to(other : like Current) : BOOLEAN bei dem ein verankerter
Typ verwendet wird: if obj_some.conforms_to(obj_other) then ...
7. Typen & Datenkonzepte: Typinformation zur Laufzeit
Typinformation zur Laufzeit
I
C++:
Der Operator typeid, der der Abfrage des dynamischen Typs eines
Objekts zur Laufzeit dient, gehört zu den jüngsten Elementen des
Sprachstandards.
if (typeid(obj) == typeid(SomeType)) {
...
} else if (typeid(obj) == typeid(OtherType)) {
...
};
Der Klassenname steht auch als Zeichenkette bereit:
if (strcmp(typeid(obj).name(), typeid(SomeType).name())) ...
I
Java:
Name des Typs eines Klassen-Objekts kann durch objekt.getClass()
erfragt werden. Des Weiteren enthält java.lang.reect Hilfsklassen zur
Aufbereitung von Typinformationen.
I
C# bietet die Operatoren is und typeof:
if (obj is ClassA) {}
if (obj.GetType() == typeof(ClassA)) {}
7. Typen & Datenkonzepte: Reihungen
Reihungen
I
Component Pascal:
I Reihungen werden statisch vereinbart. Die Elementzahl ist
durch eine positive ganze Zahl gegeben, der Indexbereich
beginnt immer bei 0, der Elementtyp ist beliebig:
VAR a : ARRAY 10 OF REAL;
I Der Wert der Variablen a ist das Feld. Zugri auf die Elemente
mit indizierten Variablen: a [0], a [9]. Die Überschreitung von
Bereichsgrenzen wird zur Laufzeit überprüft.
I Mehrdimensionale Reihungen sind möglich: VAR b : ARRAY
8, 7 OF REAL;. b [1][2] und b [1, 2] sind äquivalent.
I Als formale Parameter sind oene Reihungen (ohne Angabe
der Elementzahl) erlaubt, e.g. ARRAY OF INTEGER;
I Reihungen können dynamisch erzeugt werden, wenn ein Zeiger
auf eine oene Reihung vereinbart ist:
VAR openArr : POINTER TO ARRAY OF REAL;
...
NEW (openArr, 64);
7. Typen & Datenkonzepte: Reihungen
Reihungen
I
Eiel:
I Reihungen werden als Objekte einer Bibliotheksklasse
dynamisch erzeugt. Der Indexbereich ist durch zwei
ganzzahlige Werte festgelegt, der Elementtyp ist beliebig:
a : ARRAY[REAL].
I Der Wert der Variablen a ist ein Bezug auf ein Objekt des
Typs ARRAY[REAL], der von der generischen Klasse ARRAY
abgeleitet ist.
I Erzeugung eines Objekts: create a.make(0, 9);
I Zugri auf die Elemente erfolgt ausschlieÿlich über
Zugrisroutinen: a.put (0, x), x := a.item (9)
I Für den Lesezugri gibt es auch eine Inx-Notation: x := a @ 9
I Die Überschreitung von Bereichsgrenzen wird durch
Zusicherungen (Vorbedingungen, Invarianten) geprüft.
I Mehrdimensionale Reihungen sind durch geschachtelte
Vereinbarungen b : ARRAY [ARRAY [REAL]] oder spezielle
Klassen möglich.
7. Typen & Datenkonzepte: Reihungen
Reihungen
I
C++:
I Eigentlich gibt es in C/C++ keine Reihungen, sondern nur
eine Reihungsschreibweise für Zeiger.
I Die Elementzahl ist durch eine positive ganze Zahl gegeben,
der Indexbereich beginnt immer bei 0, der Elementtyp ist
beliebig: oat a [10];
I Der Wert der Variablen a ist ein Bezug auf das Feld.
I Zugri auf die Elemente mit indizierten Variablen oder
Zeigerarithmetik: a[0] ist äquivalent mit *a; a[9] ist äquivalent
mit *(a + 9)
I Die Überprüfung der Überschreitung von Bereichsgrenzen ist
eine seltene Kompiliereroption. Die Bereichsgrenzen sind
zudem zur Laufzeit nicht bekannt! Sie müssen daher bei
Bedarf in zusätzlichen Variablen mitgeführt werden.
I Es empehlt sich, in C++ auf die von C übernommenen
Reihungen sowie die Zeigerarithmetik weitgehend zu verzichten
und stattdessen die generische vector-Bibliotheksklasse der
STL zu verwenden, da diese sicherer ist.
7. Typen & Datenkonzepte: Reihungen
Reihungen
I
Java:
type
Verbund (Record) mit n + 1
Attributen (ein zusätzlichs Attribut enthält die Länge)
a[i] bezeichnet den Zugri auf die i -te Komponente der
I In Java wird eine Reihung mit
n
Elementen vom Typ
aufgefasst als ein Zeiger auf einen
I
Reihung a, a.length gibt die Länge der Reihung an
I Deklaration einer Reihung mit Elementen vom Typ
Länge
n:
type und
type[] var = new type[n];
I Standardwerte (Defaultwerte) sind z.B.: int: 0, double: 0.0,
boolean: false
I Sofort Anfangswerte zuweisen (Initialisierung):
type[] var =
{v0 ,
...,
v
n
−1 }
I Mehrdimensionale Reihungen sind durch Deklarierung
n
n ]; mit Dimensionsangabe
{f0 ,..., f };
type[]...[] var = new type[ 1 ]...[
i
oder geschachtelte Initialisierung type[][] var =
f
( 0 ,...,
f
n
sind Reihungen vom Typ type) möglich.
n
7. Typen & Datenkonzepte: Zeichenketten
I
Component Pascal: Zeichenketten sind Reihungen von
Zeichen.
I Sie werden mit dem Zeichen 0X abgeschlossen (siehe C++)
I Deklarierung: VAR s : ARRAY 10 OF CHAR;
I Es gibt ein Bibliotheksmodul
Strings mit Prozeduren zur
Zeichenkettenverarbeitung.
I
Eiel: Zeichenketten werden als Objekte einer
Bibliotheksklasse dynamisch erzeugt.
I Die Länge ist durch einen ganzzahligen Wert festgelegt.
I Der Wert der Gröÿe s ist ein Bezug auf ein Objekt der Klasse
STRING: s :
STRING
I Erzeugung eines Objekts: create s.make(10)
I Die Klasse enthält viele Routinen zur
Zeichenkettenverarbeitung.
7. Typen & Datenkonzepte: Zeichenketten
I
C++: Zeichenketten sind als Zeiger auf Zeichen oder als
Reihungen von Zeichen darstellbar.
I char * s;, char t[10];
I Eine Zeichenkette wird durch das Zeichen 0 oder ' \0'
abgeschlossen. Dies erlaubt eine eziente Speicherung:
char str1[] = { 'F', 'e', 'i', 'e', 'r', '\0' };
I Die Überschreitung von Bereichsgrenzen wird i.A. nicht geprüft
(kein Laufzeitfehler), sondern führt zu fehlerhaften Zugrien
auf fremde Speicherbereiche.
I Es gibt eine umfangreiche ANSI-C-Bibliothek
string.h mit
C++-
Funktionen zur Zeichenkettenverarbeitung, sowie eine
Bibliotheksklasse
string, deren Benutzung vorzuziehen ist.
7. Typen & Datenkonzepte: Zeichenketten
I
Java: Zeichenketten werden durch den Datentyp String
realisiert:
I Der Datentyp String ist in Java kein einfacher Datentyp wie
etwa int. Eine Variable vom Typ String enthält einen Verweis
auf ein Objekt vom Typ String. Dies ist deswegen nötig, weil
Strings unterschiedliche Längen annehmen können.
I Strings werden in Anführungszeichen gesetzt:
String s;
s = Hallo!;
I
C#: Zeichenketten sind Objekte der Klasse String
I Die Klasse String ist Standardklasse in
System
I Ein String-Objekt ist eine sequenzielle Auistung von
System.Char-Objekten, die eine Zeichenfolge darstellen
I
Für beide Sprachen gilt: Ein String-Objekt wird unveränderlich
(schreibgeschützt) genannt, weil dessen Wert nach dem
Erstellen nicht mehr geändert werden kann. Methoden, die ein
String-Objekt scheinbar ändern, geben in Wirklichkeit ein
neues String-Objekt zurück, das die Änderung enthält.
7. Typen & Datenkonzepte: Verbunde
Verbunde
I
Component Pascal: Die Typen der Attribute sind beliebig:
I Beispiel:
VAR r :
RECORD
name : ARRAY 20 OF CHAR;
age : INTEGER;
salary : REAL;
END;
I Zugri auf Elemente: r.name, r.age, r.salary
I
Eiel: Verbunde können als Klassen realisiert werden. Die
Attribute sind von auÿen nicht zugreifbar. Schreibzugrie
müssen mit Zugrisroutinen realisiert werden. Dies entspricht
dem Konzept der Datenabstraktion.
7. Typen & Datenkonzepte: Verbunde
Verbunde
I
C++: Die Typen der Attribute sind beliebig:
I Beispiel:
struct {
char name[20];
int age;
oat salary;
} r;
I Zugri auf Elemente: r.name, r.age, r.salary
I
I
In Java als Klasse realisierbar: class Verbund { Elementliste };
In C# als Klasse (wie Java) oder durch struct realisierbar.
7. Typen & Datenkonzepte: Mengen
Mengen
I
I
I
I
Component Pascal: Die Elemente einer Menge sind ganze
Zahlen aus kleinen Wertebereich (0 ... 31): VAR s : SET;
Es gibt Mengenoperatoren und -prozeduren.
Eiel: Mengen mit beliebigem Elementtyp werden als Objekte
einer generischen Bibliotheksklasse dynamisch erzeugt. Der
Elementtyp ist eine beliebige Klasse, e.g.: s : SET [INTEGER];
Die Klasse enthält viele Routinen, darunter Mengenoperatoren
und Zugrisroutinen auf Elemente.
Java: Für Mengen sieht die Java-Bibliothek die Schnittstelle
java.util.Set vor. Eine Menge deniert neben Operationen für
Anfrage und Einfügen von Elementen auch Funktionen für
Schnitt und Vereinigung von Mengen.
C#: Keine direkte Unterstützung. Es gibt u.a. HashSet<T>
(> .NET 3.5) und SortedSet<T> (> .NET 4.0).
7. Typen & Datenkonzepte: Einfache Typen
Zeichen & Zahlen
I
I
Component Pascal: Zeichen und Zahlen sind unterscheidbare
Typen mit unterschiedlichen Operatoren. Die Anpassung
erfolgt explizit mit Standardfunktionen:
VAR c : CHAR; i : INTEGER;
c := 'A';
c := CHR (65);
i := 65;
i := ORD (0AX);
i := ORD ('A') + ORD ('B');
Eiel bietet konzeptuell dasselbe wie Component Pascal, nur
mit den Funktionen charconv und charcode der Klasse
BASIC_ROUTINES statt CHR und ORD.
7. Typen & Datenkonzepte: Einfache Typen
Zeichen & Zahlen
I C++: Zeichen und Zahlen werden kaum unterschieden. Auf
Zeichen sind arithmetische Operationen anwendbar:
char c; int i;
c = 'A';
c = 65;
i = 65;
i = 'A' + 'B';
I Java: Zwischen Zeichen und Zahlen kann gecastet werden.
Zuordnungswerte sind durch den Unicode festgelegt:
char c; int i;
c = 'A';
c = (char)65;
i = (int)c;
i = (int)'A';
I C#: Umwandlung zwischen Zeichen und Zahlen erfolgt
e.g. durch Funktionen der Systemklasse Convert
7. Typen & Datenkonzepte: Einfache Typen
Aufzählungen
I
Component Pascal:
Die aus
Pascal und Modula-2 bekannten
Aufzählungstypen elen dem Prinzip der Minimierung der Sprachkonzepte
zum Opfer. Aufzählungen müssen mit ganzzahligen Konstanten realisiert
werden, wobei Typsicherheit verlorengeht:
CONST
red = 0;
green = 1;
blue = 2;
numColours = 3;
VAR colour : INTEGER;
ASSERT ((0 <= colour) & (colour <= numColours), BEC.invariant);
I
Eiel:
Die den Bezeichnern red, green, blue zugeordneten Werte sind
klassenweit eindeutige konsekutive positive Ganzzahlen. Die Einhaltung
des Wertebereichs wird hier mit einer Invariante geprüft.
red, green, blue : INTEGER is unique
colour : INTEGER
invariant
colour = red or colour = green or colour = blue
7. Typen & Datenkonzepte: Einfache Typen
Aufzählungen
I
C++:
Die Aufzählungstypen sind aus C übernommen.
enum Colour {red, green, blue};
Colour colour;
Aufzählungen sind mit ganzen Zahlen verträglich. Der Aufzählungstyp ist
implementierbar:
enum Colour {red = 0, green = 9, blue = -1 };
I
Java:
Aufzählungen können durch Klassen implementiert werden:
public class Colour {
public static nal red = 0;
public static nal green = 1;
public static nal blue = 2;
}
public class ColourClient {
int colour = Colour.red;
}
I
C#: enum-Konstrukt ähnlich wie in C++
7. Typen & Datenkonzepte: Konstanten
Konstanten
I
Component Pascal:
I Beispiele für literale Konstanten: 'a', 1, 2.3, 4.5E-6, ghe
I Konstantennamen für einfache Werte sind in einer
Konstantenvereinbarung denierbar. Es handelt sich um
Übersetzungszeitkonstanten: CONST pi = 3.14;
I
Eiel:
I Beispiele für literale Konstanten: 'a', 1, 2.3, 4.5E-6, ghe
I Namen für Werte von Basistypen sind in einer Merkmals-
vereinbarung einer Klasse denierbar: pi : REAL = 3.14;
I In diesem Beispiel ist eine Einmalfunktion günstig einsetzbar:
pi : REAL
once
Algorithmus zur
pi-Berechnung
Result := Ausdruck
end
I Kommt es auf den Wert nicht an, kann das Wortsymbol unique
verwendet werden: left, right : INTEGER is unique;
I Einmalfunktionen können auch für konstante Objekte und zur
Bildung von Laufzeitkonstanten verwendet werden.
7. Typen & Datenkonzepte: Konstanten
Konstanten
I
C++:
I Beispiele für literale Konstanten: 'a', 1, 2.3, 4.5E-6, ghe, 012
(Oktal), 0xAFFE (Hexadezimal)
I
C kennt keine Konstantennamen.
Solche sind aber mit einer
Vorübersetzerdirektive denierbar. Sie werden vor der Kompilation
substituiert: #dene pi (3.14)
I
C++ bietet aber richtige Konstanten, deren Benutzung man
vorziehen sollte: const oat pi = 3.14;
I
Java bietet das nal Konstrukt, welches in Klassen nur in Kombination
mit static Sinn macht:
public static nal oat pi = 3.14;
I
C#:
bietet entsprechend das
const Konstrukt:
public const double pi = 3.14;
8. Ablaufsteuerung & alg. Konzepte: Routinen
Unter Routinen verstehen wir Prozeduren und Funktionen. Die
syntaktischen Einheiten zur Vereinbarung von Routinen sind in
jeder Sprache anders bezeichnet.
8. Ablaufsteuerung & alg. Konzepte: Prozeduren
Prozeduren in den verschiedenen Sprachen
I
Component Pascal:
I
I
C++, Java, C#:
Eiel:
8. Ablaufsteuerung & alg. Konzepte: Funktionen
Funktionen in den verschiedenen Sprachen
I
Component Pascal:
I
I
C++, Java, C#:
Eiel:
8. A& AK: Parameter & Ergebnisübergabe
8. Ablaufsteuerung & alg. Konzepte: Zusicherungen
Zusicherungen in Component Pascal
I
I
I
Es gibt allgemeine Zusicherungen in Form vordeklarierter
Prozeduren:
ASSERT (Bedingung);
ASSERT (Bedingung, Fehlernummer);
Ist die Bedingung falsch, so wird der Programmablauf mit
einem Trap abgebrochen.
Zur Information werden die Fehlernummer, der Aufrufkeller
mit allen Variablen und die Abbruchstelle im Quellprogramm
angezeigt.
8. Ablaufsteuerung & alg. Konzepte: Zusicherungen
Zusicherungen in Eiel
I
I
I
Ein wichtiges Entwurfsziel ist, dass sich die Sprache als
Spezikationssprache eignen und die Entwicklung korrekter
Programme unterstützen soll.
Den Sprachkonstrukten liegt das Kunden-Lieferanten-Modell
(client-supplier-model) zugrunde, auf dem auch eine
Entwicklungsmethode aufbaut.
Dabei werden Prozeduren mit Vor- und Nachbedingungen,
Klassen mit Invarianten speziziert.
8. Ablaufsteuerung & alg. Konzepte: Zusicherungen
Entsprechend bietet
Eiel die folgenden Arten von Zusicherungen:
I
Allgemeine Zusicherung als Anweisung:
I
Vor- und Nachbedingungen von Routinen als Abschnitte:
check Bedingung end;
require Vorbedingungen
ensure Nachbedingungen
Diese Abschnitte werden vererbt, d.h. eine Redenition einer Routine
muss sich an die geerbte Spezikation halten. Sie darf nur die
Vorbedingungen abschwächen und die Nachbedingungen verstärken.
I
Invarianten von Klassen als Abschnitt:
invariant Konsistenzbedingungen
Die Konsistenzbedingungen müssen vor und nach jedem Aufruf einer
Routine gelten. Der Abschnitt wird vererbt, d.h. eine Unterklasse einer
Klasse muss sich an die geerbte Spezikation halten. Sie darf die
Invarianten nur verstärken.
I
Invarianten und Varianten von Schleifen als Abschnitte:
invariant Bedingung
variant nichtnegativ-ganzzahliger Ausdruck
8. Ablaufsteuerung & alg. Konzepte: Zusicherungen
Zusicherungen in Eiel
I
I
I
Die require-, ensure- und invariant-Abschnitte sind in
objektorientierte Konzepte integriert.
Ist eine Prüfbedingung falsch, so wird eine sprachdenierte
Ausnahme (exception) ausgelöst. Diese Ausnahme kann an
denierter Stelle auf programmiererdenierte Weise behandelt
werden.
Ist keine Ausnahmebehandlung programmiert, so wird der
Programmablauf abgebrochen. Die Überprüfung von
Zusicherungen ist selektiv zur Laufzeit steuerbar.
8. Ablaufsteuerung & alg. Konzepte: Zusicherungen
Zusicherungen in C++
I
Zusicherungen sind durch eine Bibliothek mit der Schnittstellendatei
assert.h unterstützt. Dort ndet sich von ANSI-C das Vorübersetzermakro
assert(Bedingung);
I
Ist die Prüfbedingung falsch, so wird der Programmablauf durch Aufruf
der Funktion abort () abgebrochen.
I
Zur Information werden der Wert der Bedingung (die ein beliebiger
Ausdruck ist), der Name der Quelldatei und die Zeilennummer der
Abbruchstelle ausgegeben.
I
Die Vorübersetzerdirektive #dene NDEBUG schaltet die Überprüfung
der Zusicherungen ab (vor der Kompilation).
I
C++ bietet zusätzlich die generische Funktion
Assert (Bedingung, Ausnahme);
I
Ist die Prüfbedingung falsch, so wird die übergebene
programmiererdenierte Ausnahme (exception) ausgelöst. Die Reaktion
hängt dann von der Ausnahme und ihrer Behandlung ab.
I
Die Überprüfung dieser Zusicherungen ist auch mit NDEBUG steuerbar.
Mit Hilfe von Ausnahmen kann man auch eigene Prüunktionen
programmieren.
8. Ablaufsteuerung & alg. Konzepte: Zusicherungen
Zusicherungen in Java
I
Java bietet Zusicherungen mit Release 1.4 in Form eines Sprachkonstrukts
I
Zusicherungen werden mit dem Schlüsselwort assert eingeleitet, dem
booleschen Ausdruck kann eine Zeichenkette folgen:
assert Bedingung : Zeichenkette;
I
Beim Aufruf des Interpretierers, der
Java Virtual Machine, ist anzugeben,
ob die Zusicherungen zur Laufzeit geprüft werden soll:
java -enableassertions MyClass
java -ea MyClass
oder nicht:
java -disableassertions MyClass
java -da MyClass
I
Die Standardeinstellung ist, Zusicherungen nicht zu prüfen
I
Verletzte Zusicherung führt zu Abbruch mit Fehlermeldung, z.B.:
Exception in thread "main" java.lang.AssertionError: Zeichenkette
at MyClass.main(MyClass.java:5)
8. Ablaufst. & alg. Konzepte: Anweisungen
Example: WITH t: CenterTree DO i := t.width; c := t.subnode END
8. Ablaufst. & alg. Konzepte: Syntaktischer Zucker
Ein Programmkonstrukt weist eine Unstetigkeitsstelle auf, wenn zwei
Programme, die dieses Konstrukt verwenden und sich in nur einem
Zeichen unterscheiden, verschiedene Semantik haben.
Component Pascal, Eiel:
I Alle Steuerkonstrukte benutzen Wortsymbole, um Anweisungsfolgen
zu klammern.
I Deshalb ist keine Verbundanweisung erforderlich. Das schlieÿende
END bzw. end beseitigt Unstetigkeitsstellen und Zweideutigkeiten
älterer Sprachen.
I In
Component Pascal ist das Semikolon ; Endezeichen bei
Vereinbarungen und Trennzeichen zwischen Anweisungen.
I In
Eiel ist das Semikolon bei Vereinbarungen und Anweisungen ein
optionales Trennzeichen, d.h. es kann auch weggelassen werden,
weil die Syntax so deniert ist, dass es auf ein Semikolon mehr oder
weniger nicht ankommt.
I Der empfohlene Stil ist jedoch, trennende Semikola zwecks besserer
Lesbarkeit hinzuschreiben.
8. Ablaufst. & alg. Konzepte: Syntaktischer Zucker
C++:
I Steuerkonstrukte erwarten immer eine einzelne Anweisung und
enden meist ohne Wortsymbol. Deshalb ist eine Verbundanweisung
erforderlich, sie verwendet die geschweiften Klammern:
{ Anweisungen }
I Manche Konstrukte haben Unstetigkeitsstellen. Beispiel:
while (i < 9) ; i++;
while (i < 9) i++;
I Manche Konstrukte liefern Zweideutigkeiten, die durch zusätzliche
Sprachregeln aufgelöst werden müssen. Beispiel:
if (i < 9) if (k > 1) i = k--; else i = k++;
I Das Semikolon ist bei manchen Anweisungen ein Endezeichen
(Deklaration, Ausdruck, do, break, return), bei anderen nicht. Ein
defensiver Schreibstil ist, das Semikolon als Endezeichen bei jeder
Anweisung zu setzen.
8. Ablaufst. & alg. Konzepte: Alternative Werte
C++
Component Pascal
I
Eiel
case dient nur als Einsprungmarke, von da an werden alle folgenden
Anweisungen ausgeführt bis zur ersten break-Anweisung; diese führt zu
einem Sprung ans Ende der switch-Anweisung.
I
Vergessene break-Anweisungen sind eine Fehlerquelle.
I
Es gibt keine Listen und Intervalle von Fällen, diese können durch
mehrere
case ohne abschlieÿendes break simuliert werden.
8. A & AK: Wiederholungsanweisung
Component Pascal
C++
Eiel
Konklusion
Der 'Informatik 3'-Student sollte
I abstrakte (programmiersprachenunabhängige) Problemstellungen
und Konzepte
I erfassen und/oder modellieren können
I in den verschiedenen Programmiersprachen implementieren
und (teil-)spezizieren können
I Programm(teil)e von einer in eine andere Programmiersprache
übersetzen können
I Einsatzmöglichkeiten von Programmiersprachen erkennen können
(wann ist Sprache A der Sprache B vorzuziehen und warum?)
I mit den folgenden Konzepten vertraut sein:
I
I
Typen: Datentypen, Semantiken, Morph. & Dyn. Binden...
Strukturen: Algorithmen, Funktionen, Methoden, Module,
Abstrakte Datenstrukturen, Klassen...
I
Objektorientierte Programmierung:
Klassen, abstrakte
Datentypen, Vererbung/Erweiterung...
I
Abstraktion:
Datenabstraktion, Schnittstellen, Generizität...
Herunterladen