obj2 - Informatik
obj2 - Informatik obj2 - Informatik
Fortgeschrittene Aspekte objektorientierter Programmierung Prof. Dr. Arnd Poetzsch-Heffter — AG Softwaretechnik Wintersemester 02/03
- Seite 2 und 3: Inhalt
- Seite 4 und 5: 1. Einleitung
- Seite 6 und 7: 1.1 Überblick 6 A. Poetzsch-Heffte
- Seite 8 und 9: 1.1 Überblick 8 • konzeptionelle
- Seite 10 und 11: 1.1 Überblick 10 Beispiel(Programm
- Seite 12 und 13: 1.1 Überblick 12 Typisierung: Typi
- Seite 14 und 15: 1.1 Überblick 14 class Entry { ET
- Seite 16 und 17: 1.1 Überblick 16 Spezifikation von
- Seite 18 und 19: 1.1 Überblick 18 Prüfen und Verif
- Seite 20 und 21: 1.1 Überblick 20 Formale Techniken
- Seite 22 und 23: 1.1 Überblick 22 1. Einleitung ◦
- Seite 24 und 25: 1.1 Überblick 24 ◦ Verfeinerung
- Seite 26 und 27: 1.2 Formale und notationelle Grundl
- Seite 28 und 29: 1.2 Formale und notationelle Grundl
- Seite 30 und 31: 1.2 Formale und notationelle Grundl
- Seite 32 und 33: 1.2 Formale und notationelle Grundl
- Seite 34 und 35: 1.2 Formale und notationelle Grundl
- Seite 36 und 37: 1.2 Formale und notationelle Grundl
- Seite 38 und 39: 1.2 Formale und notationelle Grundl
- Seite 40 und 41: 1.2 Formale und notationelle Grundl
- Seite 42 und 43: 1.2 Formale und notationelle Grundl
- Seite 44 und 45: 2. Grundlagen objektorientierter Sp
- Seite 46 und 47: 2.1 Konzepte objektorientierter Pro
- Seite 48 und 49: 2.1 Konzepte objektorientierter Pro
- Seite 50 und 51: 2.1 Konzepte objektorientierter Pro
Fortgeschrittene Aspekte<br />
objektorientierter Programmierung<br />
Prof. Dr. Arnd Poetzsch-Heffter — AG Softwaretechnik<br />
Wintersemester 02/03
Inhalt
1. Einleitung<br />
Inhalt<br />
2. Grundlagen objektorientierter Sprachen<br />
3. Techniken zum Prüfen objektorientierter Programme<br />
4. Spezifikation objektorientierter Programme<br />
5. Verifikation spezifizierter Eigenschaften<br />
6. Ausblicke<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
3
1. Einleitung
1.1 Überblick<br />
1. Einleitung<br />
1.2 Formale und notationelle Grundlagen<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
5
1.1 Überblick 6<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
1.1 Überblick
1.1 Überblick 7<br />
Ausgangspunkt:<br />
• Kenntnis objektorientierter Programmierung (z.B. Java)<br />
Lernziele:<br />
• technische Vertiefung in:<br />
◦ Semantik<br />
◦ Typisierung<br />
⊲ bessere Parametrisierung<br />
⊲ Ausdruck weiterer Eigenschaften<br />
◦ Spezifikation von Programmeigenschaften<br />
◦ Prüfen und Verifikation<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.1 Überblick 8<br />
• konzeptionelle Vertiefung in:<br />
◦ objektorientierter Programmierung<br />
◦ objektorientierter Modellierung<br />
• Werkzeugentwicklung in diesem Bereich<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.1 Überblick 9<br />
Semantik<br />
Zwei zentrale Aspekte:<br />
• Spezifikation von Programmeigenschaften<br />
• Spezifikation der Programmiersprache<br />
Beispiel(Semantik für Programmeigenschaften):<br />
public class List {<br />
int length;<br />
ListElems le;<br />
//@ invariant length == le.leng();<br />
...<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.1 Überblick 10<br />
Beispiel(Programmiersprachensemantik):<br />
class IntPair {<br />
private int a;<br />
private int b;<br />
IntPair( int ai, int bi ){ a = ai; b = bi; }<br />
int sum(){ return this.add(); }<br />
private int add(){ return a+b; }<br />
}<br />
class IntTriple extends IntPair {<br />
private int a;<br />
IntTriple( int ai,int bi,int ci ){ super(ai,bi); a = ci; }<br />
int sum(){ return this.add(); }<br />
private int add(){ return super.sum() + a; }<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.1 Überblick 11<br />
public class PrivateTest {<br />
public static void main( String[] arg ) {<br />
IntPair ip = new IntPair(3,9);<br />
IntTriple it = new IntTriple(1,2,27);<br />
System.out.println( ""+ip.sum()+" "+it.sum() );<br />
}<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.1 Überblick 12<br />
Typisierung:<br />
Typisierung<br />
Beschreibung von einfachen Eigenschaften<br />
• im Rahmen der Programmiersprachen<br />
• mit automatischer Prüfung durch den Übersetzer<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.1 Überblick 13<br />
Beispiel(Parametrischer Polymorphismus):<br />
class LinkedList {<br />
Entry header = new Entry(null, null, null);<br />
int size = 0;<br />
}<br />
LinkedList() { ... }<br />
ET getLast() { ... }<br />
ET removeLast() { ... }<br />
void addLast(ET e) { ... }<br />
int size() { return size; }<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.1 Überblick 14<br />
class Entry {<br />
ET element;<br />
Entry next;<br />
Entry previous;<br />
}<br />
Entry(ET element, Entry next, Entry previous) {<br />
this.element = element;<br />
this.next = next;<br />
this.previous = previous;<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.1 Überblick 15<br />
class Test {<br />
public static void main( String[] args ) {<br />
LinkedList ls = new LinkedList();<br />
ls.addLast("erstes Element");<br />
ls.addLast("letztes Element");<br />
ls.getLast().indexOf("Elem"); // liefert 8<br />
}<br />
LinkedList lo = new LinkedList();<br />
lo.addLast( new Object() );<br />
lo.addLast( new Object() );<br />
lo.getLast().indexOf("Elem"); // Programmierfehler,<br />
} // der vom Uebersetzer automatisch entdeckt wird<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.1 Überblick 16<br />
Spezifikation von Programmeigenschaften<br />
Spezifikation:<br />
• Beschreibung aussagekräftiger Eigenschaften<br />
◦ von Programmteilen oder -Schnittstellen<br />
◦ mit zusätzlichen Sprachmitteln<br />
• Prüfung mit unterschiedlichen Techniken<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.1 Überblick 17<br />
Beispiel(Methodenspezifikation):<br />
public class IntMathOps {<br />
/*@ public normal_behavior<br />
@ requires y >= 0<br />
@ modifiable \nothing<br />
@ ensures \result * \result
1.1 Überblick 18<br />
Prüfen und Verifikation<br />
Aufgabe:<br />
Nachweis, dass beschriebenen Eigenschaften von<br />
Implementierung erfüllt werden.<br />
Techniken:<br />
• vollautomatisch vs. halbautomatisch/interaktiv<br />
• vollständig vs. teilweise<br />
• statisch vs. dynamisch<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.1 Überblick 19<br />
Beispiel(Korrektheit):<br />
Aufgabe:<br />
Beweise, dass folgende Implementierung der Methode isqrt<br />
obige Spezifikation erfüllt.<br />
public static int isqrt( int y ){<br />
int count = 0, sum = 1;<br />
while (sum
1.1 Überblick 20<br />
Formale Techniken auf der Entwurfsebene<br />
Exemplarisch betrachten wir UML-Klassendiagramme<br />
annotiert mit OCL-Bedingungen (Object-constraint<br />
language)<br />
Beispiel(Annotiertes Klassendiagramm):<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.1 Überblick 21<br />
Statisches Modell mit Bedingungen<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.1 Überblick 22<br />
1. Einleitung<br />
◦ Überblick<br />
Aufbau, Inhalt, Literatur<br />
◦ formale und notationelle Grundlagen<br />
2. Grundlagen objektorientierter Sprachen<br />
◦ Spracheigenschaften<br />
◦ Semantik objektorientierter Sprachen<br />
◦ Eigenschaften objektorientierter Programme<br />
◦ Modularität und Kapselung<br />
3. Techniken zum Prüfen objektorientierter Programme<br />
◦ Einführung in die Bedeutung von Typsystemen<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.1 Überblick 23<br />
◦ Typinformation und ihre statische und dynamische Prüfung<br />
◦ Typsicherheit<br />
◦ parametrische Typsysteme<br />
◦ virtuelle Klassen<br />
◦ erweiterte Typsysteme<br />
4. Spezifikation objektorientierter Programme<br />
◦ Grundlagen, Abstraktion, Kapselung<br />
◦ Spezifikation funktionaler Eigenschaften<br />
◦ Konformität von Subklassen (behavioral subtyping)<br />
◦ Spezifikation von Umgebungseigenschaften<br />
◦ Klassen- und Modulinvarianten<br />
◦ Modularitätsproblematik<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.1 Überblick 24<br />
◦ Verfeinerung von Spezifikation<br />
5. Verifikation spezifizierter Eigenschaften<br />
◦ erweitertes dynamisches Prüfen<br />
◦ erweitertes statisches Prüfen<br />
◦ Programmverifikation<br />
◦ Strategien zur interaktiven Verifikation<br />
◦ Generierung schwächster Vorbedingungen<br />
6. Ausblicke<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.1 Überblick 25<br />
Literatur:<br />
• kein Buch, das gesamten Stoff abdeckt<br />
• Bücher über Vorlesungsteile<br />
• wissenschaftliche Artikel<br />
• Sprachspezifikationen<br />
Literatur wird kapitel-/abschnittsweise angegeben.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.2 Formale und notationelle Grundlagen 26<br />
1.2 Formale und notationelle Grundlagen<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.2 Formale und notationelle Grundlagen 27<br />
• Die Sprache der (sortierten) Prädikatenlogik :<br />
◦ Signaturen<br />
◦ Terme<br />
◦ Formeln<br />
• Algebraische Datentypen<br />
• Abschließende Bemerkungen<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.2 Formale und notationelle Grundlagen 28<br />
Die Sprache der Prädikatenlogik<br />
Definition(Signatur):<br />
Eine Signatur Σ = (S, F ) besteht aus<br />
• einer Menge S von Sorten (Namen für Datentypen)<br />
• einer Menge F von Funktionssymbolen (Namen für<br />
Funktionen)<br />
so dass jede f ∈ F eine Funktionalität<br />
f : s1 × . . . × sn → s hat mit s1, . . . , sn, s ∈ S (n ≥ 0)<br />
Nullstellige Funktionen werden Konstanten genannt.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.2 Formale und notationelle Grundlagen 29<br />
Beispiel(Signatur):<br />
1. Signatur der ganzen Zahlen:<br />
S = {Integer}<br />
F = {0 : → Integer<br />
succ : Integer → Integer<br />
pred : Integer → Integer<br />
+ : Integer × Integer → Integer<br />
− : Integer × Integer → Integer<br />
. . .}<br />
ΣINTEGER = (S, F )<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.2 Formale und notationelle Grundlagen 30<br />
2. Signatur für Keller mit Elementen aus der Sorte Elem<br />
S = {Elem, Stack}<br />
F = {emptyStack : → Stack<br />
push : Stack × Elem → Stack<br />
pop : Stack → Stack<br />
top : Stack → Elem}<br />
ΣSTACK = (S, F )<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.2 Formale und notationelle Grundlagen 31<br />
Bemerkung:<br />
• Im Folgenden gehen wir davon aus, dass<br />
◦ jede Signatur die Sorte Bool enthält und<br />
◦ für jede Sorte S eine Gleichheitsfunktion<br />
=S: S × S → Bool<br />
existiert.<br />
• Sorten spielen auf Spezifikationsebene die gleiche Rolle wie<br />
Typen in der Programmierung. Die terminologische<br />
Unterscheidung erleichtert im Folgenden die Trennung<br />
zwischen<br />
◦ der Sprache, die beschrieben wird, und<br />
◦ der Sprache, die zur Beschreibung verwendet wird.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.2 Formale und notationelle Grundlagen 32<br />
Definition(Terme):<br />
Jede Signatur Σ = (S, F ) und S-sortierte Menge VAR von<br />
(logischen) Variablen erzeugt eine Menge T (Σ, VAR) von<br />
Termen, die aus Funktionssymbolen aus F und Variablen aus<br />
VAR (entsprechend der Funktionalitäten der<br />
Funktionssymbole und der Sorten der Variablen) bestehen.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.2 Formale und notationelle Grundlagen 33<br />
Beispiel(Terme):<br />
• Sei VARSTACK = {e : Elem, s : Stack},<br />
push(s, e), pop(push(s, e)), top(pop(push(s, e))),<br />
top(push(emptyStack, e)) sind Terme aus<br />
T (ΣSTACK, VARSTACK)<br />
• succ(0), succ(0) + succ(succ(0)) ∈ T (ΣINT EGER, ∅)<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.2 Formale und notationelle Grundlagen 34<br />
Definition(Formeln):<br />
Sei Σ = (S, F ) eine Signatur, VAR eine S-sortierte Menge<br />
logischer Variablen und sei die Menge der Σ–Terme der<br />
Sorte s, bezeichnet als T (Σ, VAR)s. Die Menge der<br />
Σ–Formeln F (Σ) ist die kleinste Menge, die die folgenden<br />
Eigenschaften erfüllt:<br />
• jeder Term der Sorte Bool ist in F (Σ);<br />
• wenn G, H ∈ F (Σ), dann sind<br />
¬G, (G ∧ H), (G ∨ H), (G ⇒ H) und (G ⇔ H) in F (Σ);<br />
• wenn Xs ∈ VARs und G ∈ F (Σ), dann<br />
(∀Xs : G), (∃Xs : G) ∈ F (Σ).<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.2 Formale und notationelle Grundlagen 35<br />
Bemerkung:<br />
• Um Klammern zu vermeiden, benutzen wir die folgenden<br />
Präzedenzen (von starke zu schwache Bindung):<br />
¬, ∧, ∨, ⇒, ⇔, ∀, ∃.<br />
• Prädikatenlogik wird im Folgenden hauptsächlich als<br />
Spezifikationssprache verwendet.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.2 Formale und notationelle Grundlagen 36<br />
Algebraische Datentypen<br />
Beispiel(algebraische Datentypen):<br />
Sei Elem eine bereits definierte Sorte.<br />
Dann definiert<br />
data type<br />
ElemList = emptyElemList ()<br />
| app( first:Elem, rest:ElemList )<br />
end<br />
die Signatur (S,F):<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.2 Formale und notationelle Grundlagen 37<br />
S = {ElemList}<br />
F = {emptyElemList : → ElemList<br />
app : Elem × ElemList → ElemList<br />
first : ElemList → Elem<br />
rest : ElemList → ElemList<br />
isemptyElemList : ElemList → Bool<br />
isapp : ElemList → Bool},<br />
wobei die Sorten und Funktionen die übliche Bedeutung<br />
haben. emptyElemList und app heißen die<br />
Konstruktorfunktionen (Konstruktoren) von (S,F).<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.2 Formale und notationelle Grundlagen 38<br />
Abkürzend läßt sich der Datentyp ElemList auch so<br />
definieren:<br />
data type<br />
ElemList = list of Elem<br />
end<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.2 Formale und notationelle Grundlagen 39<br />
Definition(Syntax algebraischer Datentypen):<br />
Deklarationen algebraischer Datentypen haben die Form:<br />
data type<br />
+<br />
end<br />
wobei<br />
::= <br />
| <br />
::= "list of" <br />
::= <br />
( "|" )*<br />
::= <br />
"(" [ Komponentendekl ("," Komponentendekl)* ] ")"<br />
Komponentendekl ::= [ ":"] <br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.2 Formale und notationelle Grundlagen 40<br />
Zur Semantik algebraischer Datentypen:<br />
• unterschiedliche Konstruktorterme repräsentieren<br />
unterschiedliche Werte<br />
• alle Werte der Sorten sind erzeugt<br />
• Beweisprinzip: Induktion über den Aufbau der Terme<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.2 Formale und notationelle Grundlagen 41<br />
Bemerkung:<br />
• Algebraische Datentypdeklarationen finden sich in den<br />
meisten funktionalen Programmiersprachen und sehr vielen<br />
Spezifikationssprachen.<br />
• Wichtiges Anwendungsgebiet ist die Spezifikation der<br />
abstrakten Syntax von Programmiersprachen.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
1.2 Formale und notationelle Grundlagen 42<br />
Abschließende Bemerkungen<br />
• Weitere Spezifikationstechniken werden im Zusammenhang<br />
mit ihrer Anwendung erläutert.<br />
• Rekursive Prädikatspezifikationen werden für operationelle<br />
Semantik und Typeigenschaften benötigt.<br />
• Ziel ist hier: eine klare Sprachebene, um Eigenschaften von<br />
Programmiersprachen und von Programmen ausdrücken zu<br />
können.<br />
• Ziel ist hier nicht: Formalisierung in allen Details.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2. Grundlagen<br />
objektorientierter Sprachen
2. Grundlagen objektorientierter Sprachen<br />
2.1 Konzepte objektorientierter Programmierung<br />
2.2 Semantik objektorientierter Sprachen<br />
2.3 Eigenschaften objektorientierter Programme<br />
2.4 Modularität und Kapselung<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
44
2.1 Konzepte objektorientierter Programmierung 45<br />
2.1 Konzepte objektorientierter<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
Programmierung
2.1 Konzepte objektorientierter Programmierung 46<br />
2.1.1 Grundkonzepte :<br />
• Objektkonzept<br />
• Klassifikation und Subtyping<br />
2.1.2 Sprachliche Konzepte :<br />
• Beschreibung von Objekten<br />
• Vererbungskonzept<br />
• dynamische Methodenauswahl<br />
• Zusammenwirken der Konzepte<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 47<br />
2.1.3 Pragmatische Aspekte :<br />
• Vererbung versus Subtyping<br />
• Objektorientierte Sicht auf Prozeduren und Klassen<br />
Ziel:<br />
• Wiederholung auf abstrakterem Niveau<br />
• Zusammenhang von Konzepten und Sprachmitteln<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 48<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
2.1.1 Grundkonzepte
2.1 Konzepte objektorientierter Programmierung 49<br />
Objektkonzept<br />
,,The basic philosophy underlying object-oriented programming is to<br />
make the programs as far as possible reflect that part of the reality they<br />
are going to treat. It is then often easier to understand and to get an<br />
overview of what is described in programs. The reason is that human<br />
beings from the outset are used to and trained in the perception of what<br />
is going on in the real world. The closer it is possible to use this way of<br />
thinking in programming, the easier it is to write and understand<br />
programs.“<br />
aus: Object-oriented Programming in the BETA Programming Language<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 50<br />
Objektorientiertes Paradigma:<br />
Betrachte ein Softwaresystem als eine Menge kooperierender<br />
Objekte.<br />
a1:<br />
a2:<br />
obj1<br />
m(p1,p2) {..}<br />
m1() {..}<br />
m2( p ) {..}<br />
<strong>obj2</strong><br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
. m( 1814, "SS1999")<br />
a:<br />
<strong>obj2</strong><br />
m(p1,p2) {..}<br />
n( p,r ) {..}
2.1 Konzepte objektorientierter Programmierung 51<br />
Objekte sind eigenständige Ausführungseinheiten mit:<br />
• Zustand<br />
• Identität<br />
• Lebensdauer<br />
• Aufenthaltsort<br />
• Verhalten<br />
Im Vergleich zur prozeduralen Programmierung:<br />
• andere Programmstruktur<br />
• anderes Ausführungsmodell<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 52<br />
Konsequenz des Objektkonzepts:<br />
• saubere Schnittstellenbildung<br />
◦ öffentlich zugängliche Methoden<br />
◦ öffentlich zugängliche Attribute<br />
• Schnittstelle verbirgt Implementierung (Information<br />
Hiding)<br />
• Schnittstelle ist Basis für Verhaltensbeschreibung<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 53<br />
Klassifikation:<br />
Klassifikation und Subtyping<br />
Klassifizieren ist eine allgemeine Technik, um Wissen über<br />
Begriffe, Dinge und deren Eigenschaften hierarchisch zu<br />
strukturieren. Das Ergebnis nennen wir eine Klassifikation.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 54<br />
Beispiel(Klassifikation der Rechtsgebiete):<br />
Öffentliches<br />
Recht<br />
Bürgerliches<br />
Recht<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
Recht<br />
Privatrecht Kirchenrecht<br />
Handelsrecht Urheberrecht
2.1 Konzepte objektorientierter Programmierung 55<br />
Beispiel(Klassifikation der Wirbeltiere):<br />
Wirbeltiere<br />
Fische Lurche Reptilien Säugetiere Vögel<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
Wale Primaten Paarhufer
2.1 Konzepte objektorientierter Programmierung 56<br />
Beispiel(Klassifikation der Figuren):<br />
Ellipse<br />
Kreis<br />
Figur<br />
Vieleck<br />
Viereck Dreieck<br />
Parallelogramm<br />
Raute Rechteck<br />
Quadrat<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
Der Pfeil ↗<br />
repräsentiert die<br />
ist-ein-Beziehung.<br />
Ziel: Anwendung der<br />
Klassifikationstechnik<br />
auf Software-Objekte
2.1 Konzepte objektorientierter Programmierung 57<br />
Beobachtungen zu Klassifikationen:<br />
• Sie können sich auf Objekte oder Gebiete beziehen.<br />
• Sie können baumartig oder DAG-artig sein.<br />
• Objektklassifikationen begründen ist-ein-Beziehungen.<br />
• abstrakte Klassen vs. nicht abstrakte Klassen<br />
Prinzip der Substitution:<br />
Überall, wo Oberklassenobjekte erwartet werden, lassen sich<br />
auch Unterklassenobjekte verwenden.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 58<br />
In der Softwaretechnik:<br />
1. Klassifikation syntaktisch:<br />
Unterklassenobjekte haben größere Schnittstellen als<br />
Oberklassenobjekte (Auswirkung auf<br />
Programmiersprache).<br />
2. Klassifikation semantisch:<br />
Unterklassenobjekte bieten mindestens das Verhalten,<br />
welches Oberklassenobjekte haben.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 59<br />
Abstraktion:<br />
... das Heraussondern des unter einem bestimmten<br />
Gesichtspunkt Wesentlichen vom Unwesentlichen.<br />
[Meyers großes Taschenlexikon]<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 60<br />
Mittels Abstraktion:<br />
• ausgehend von unterschiedlichen Objekten oder Typen mit<br />
gemeinsamen Eigenschaften<br />
• Ausarbeitung eines abstrakteren Typs, der die<br />
gemeinsamen Eigenschaften zusammenfasst<br />
• entspricht dem Verkleinern der Schnittstelle<br />
• Programme, die sich nur auf diese gemeinsamen<br />
Eigenschaften stützen, arbeiten dann für alle Objekte des<br />
abstrakteren Typs.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 61<br />
Beispiel(Abstraktion):<br />
class Student {<br />
String name;<br />
int matNr;<br />
...<br />
void drucken() {<br />
System.out.<br />
println( name );<br />
System.out.<br />
println( matNr );<br />
}<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
class Professor {<br />
String name;<br />
int telNr;<br />
...<br />
void drucken() {<br />
System.out.<br />
println( name );<br />
System.out.<br />
println( telNr );<br />
}<br />
}
2.1 Konzepte objektorientierter Programmierung 62<br />
Abstraktion:<br />
• Typ Person mit<br />
Methode drucken<br />
• Algorithmus auf<br />
Basis von Person<br />
Anwendungsbeispiele:<br />
• Ein/Ausgabe-Schnittstellen<br />
• Fenstersysteme<br />
• ...<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
Person[] p = new Person[4];<br />
p[0] = new Student(...);<br />
p[1] = new Professor(...);<br />
...<br />
for(i=1; i
2.1 Konzepte objektorientierter Programmierung 63<br />
interface Person {<br />
void drucken();<br />
}<br />
class Student implements Person {<br />
...<br />
}<br />
class Professor implements Person {<br />
...<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 64<br />
Spezialisierung:<br />
... das Hinzufügen speziellerer Eigenschaften zu einem<br />
Gegenstand oder das Verfeinern eines Begriffs durch<br />
Einführen weiterer Merkmale.<br />
(z.B. berufliche Spezialisierung)<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 65<br />
Mittels Spezialisierung:<br />
• ausgehend von allgemeinen Objekten bzw. Typen<br />
• Erweiterung dieser Objekte und ihrer Implementierung<br />
• entspricht dem Hinzufügen von zusätzlichen und<br />
spezielleren Eigenschaften<br />
• Voraussetzung: spezialisierte Objekte verhalten sich<br />
konform zu den allgemeineren Objekten<br />
• Programme, die auf den allgemeineren Objekten arbeiten,<br />
arbeiten dann auch korrekt auf den spezielleren Objekten.<br />
• Vererben von Implementierungsteilen,Wiederverwendung<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 66<br />
Beispiel(Spezialisierung):<br />
Spezialisierung:<br />
• Entwickle<br />
Implementierung zu<br />
Typ Person.<br />
• Spezialisiere sie.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
class Person {<br />
String name;<br />
...<br />
void drucken(){<br />
System.out.println(name);<br />
}<br />
}
2.1 Konzepte objektorientierter Programmierung 67<br />
Vererbt werden:<br />
• Attribute<br />
• Methoden<br />
Methoden können in<br />
Subklassen<br />
überschrieben werden<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
class Student extends Person {<br />
int matNr;<br />
...<br />
void drucken(){<br />
super.drucken();<br />
System.out.println(matNr);<br />
}<br />
}<br />
class Professor extends Person {<br />
int telNr;<br />
...<br />
void drucken(){<br />
super.drucken();<br />
System.out.println(telNr);<br />
}<br />
}
2.1 Konzepte objektorientierter Programmierung 68<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
2.1.2 Sprachliche Konzepte
2.1 Konzepte objektorientierter Programmierung 69<br />
• Klassenkonzept<br />
• Prototypkonzept<br />
Beschreibung von Objekten<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 70<br />
Klassenkonzept:<br />
• Der Programmierer beschreibt nicht einzelne Objekte,<br />
sondern deklariert Klassen.<br />
• Klasse = Beschreibung der Eigenschaften, die die Objekte<br />
dieser Klasse haben sollen<br />
• Während der Programmausführung werden Objekte zu<br />
deklarierten Klassen erzeugt (Instanzieren).<br />
• Klassen können zur Ausführungszeit nicht verändert werden.<br />
• Klassendeklaration entspricht der Deklaration von<br />
Verbundtypen imperativer Sprachen.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 71<br />
Prototypkonzept:<br />
• Der Programmierer beschreibt direkt einzelne Objekte.<br />
• Neue Objekte werden durch Klonen existierender Objekte<br />
und Verändern ihrer Eigenschaften zur Ausführungszeit<br />
erzeugt.<br />
• Klonen eines Objekts obj = Erzeugen eines neuen Objekts,<br />
das die gleichen Eigenschaften wie obj besitzt.<br />
• Verändern = dem Objekt werden weitere Attribute<br />
hinzugefügt oder Methoden werden durch andere ersetzt.<br />
• Umgesetzt beispielsweise in der Sprache Self.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 72<br />
Vererbung:<br />
Vererbungskonzept<br />
Sprachlich unterstützte Wiederverwendungsmöglichkeit der<br />
Eigenschaften/des Codes einer anderen Klasse:<br />
• meist mit Subtyping gekoppelt<br />
• ergänzt um Spezialisierungsmöglichkeiten:<br />
◦ Hinzufügen von Attributen, Methoden, etc.<br />
◦ Überschreiben von Methoden<br />
◦ Verwenden überschriebener Methoden<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 73<br />
Ziele:<br />
• fehlerträchtiges Kopieren von Code vermeiden<br />
• Reduktion der Programmgröße<br />
• Spezialisierung von Schnittstellen, bei denen Kopieren<br />
bzw. Modifizieren nicht möglich ist<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 74<br />
Beispiel(Vererbung):<br />
class Person {<br />
String name;<br />
int geburtsdatum; /* in der Form JJJJMMTT */<br />
void drucken() {<br />
System.out.println("Name: "+ this.name);<br />
System.out.println("Geburtsdatum: "+ geburtsdatum);<br />
}<br />
boolean hat_geburtstag ( int datum ) {<br />
return (geburtsdatum % 10000) == (datum % 10000);<br />
}<br />
Person( String n, int gd ) {<br />
name = n;<br />
geburtsdatum = gd;<br />
}<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 75<br />
class Student extends Person {<br />
int matNr;<br />
int semester;<br />
void drucken() {<br />
super.drucken();<br />
System.out.println( "Matrikelnr: " + matNr );<br />
System.out.println( "Semesterzahl: " + semester );<br />
}<br />
Student( String n, int gd, int mnr, int sem ) {<br />
super( n, gd );<br />
matNr = mnr;<br />
semester = sem;<br />
}<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 76<br />
Dynamische Methodenauswahl<br />
Methodenauswahl:<br />
• statisch:<br />
Zur Übersetzungszeit wird jeder Aufrufstelle die<br />
auszuführende Methode zugeordnet.<br />
• dynamisch:<br />
Zur Laufzeit wird an der Aufrufstelle das Zielobjekt<br />
berechnet und in Abhängigkeit vom Zielobjekt die<br />
auszuführende Methode ausgewählt.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 77<br />
Bemerkung:<br />
Dynamische Methodenauswahl ist Voraussetzung:<br />
• für Spezialisierung<br />
• für das Arbeiten mit abstrakten Klassen und Schnittstellen<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 78<br />
Zusammenwirken der Konzepte<br />
Beispiel(Abstract Window Toolkit):<br />
1. Die Elemente der Bedienoberfläche werden als Objekte<br />
modelliert.<br />
2. Oberflächenelemente werden klassifiziert:<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 79<br />
Canvas<br />
Label<br />
Button<br />
List<br />
Choice<br />
CheckBox<br />
Scrollbar<br />
Object<br />
Component<br />
TextComponent<br />
TextArea TextField<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
Container<br />
ScrollPane Window Panel<br />
Frame<br />
Dialog<br />
FileDialog<br />
Applet
2.1 Konzepte objektorientierter Programmierung 80<br />
3. Gemeinsame Programmteile werden in der abstrakten<br />
Klasse Component zusammengefasst und von dort vererbt<br />
(über 100 Methoden).<br />
4. Viele Klassen benutzen die Klasse Component als<br />
Abstraktion.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 81<br />
Beispiel(Verwendung von Abstraktion):<br />
public class Container extends Component {<br />
...<br />
public Component getComponent(int n) { ... }<br />
public Component[] getComponents() { ... }<br />
public Component add(Component comp) { ... }<br />
public Component add(Component comp, int index) { ... }<br />
...<br />
public void remove(Component comp) { ... }<br />
...<br />
public Component getComponentAt(int x, int y) { ... }<br />
...<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 82<br />
5. Dynamische Methodenauswahl ist Vorausssetzung für das<br />
Funktionieren der Komponentenhierarchie und für die<br />
Anbindung der zu steuernden Anwendungen über die<br />
Listener-Schnittstellen.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 83<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
2.1.3 Pragmatische Aspekte
2.1 Konzepte objektorientierter Programmierung 84<br />
Vererbung versus Subtyping<br />
1. Subtyping ohne Vererbung:<br />
Objektorientierte Programmierung kann auf Vererbung<br />
verzichten, aber nicht auf Subtyping und dynamische<br />
Methodenauswahl<br />
Beispiel(Delegation statt Vererbung):<br />
interface Person {<br />
String getName();<br />
int getGeburtsdatum();<br />
void drucken();<br />
boolean hat_geburtstag( int datum );<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 85<br />
public class PersonCl implements Person {<br />
String name;<br />
int geburtsdatum; /* in der Form JJJJMMTT */<br />
}<br />
public PersonCl( String n, int gd ) {<br />
name = n;<br />
geburtsdatum = gd;<br />
}<br />
public String getName() { return name; }<br />
public int getGeburtsdatum() { return geburtsdatum; }<br />
public void drucken() {<br />
System.out.println("Name: "+ this.name);<br />
System.out.println("Geburtsdatum: "+ this.geburtsdatum);<br />
}<br />
public boolean hat_geburtstag ( int datum ) {<br />
return (this.geburtsdatum%10000) == (datum%10000);<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 86<br />
interface Student extends Person {<br />
public int getMatNr();<br />
public int getSemester();<br />
}<br />
public class StudentCl implements Student {<br />
Person personPart;<br />
int matNr;<br />
int semester;<br />
StudentCl( String n, int gd, int mnr, int sem ) {<br />
personPart = new PersonCl( n, gd );<br />
matNr = mnr;<br />
semester = sem;<br />
}<br />
public String getName() { return personPart.getName(); }<br />
public int getGeburtsdatum() { return personPart.getGeburtsdatum(); }<br />
public void drucken() {<br />
personPart.drucken();<br />
System.out.println( "Matrikelnr: " + matNr );<br />
System.out.println( "Semesterzahl: " + semester );<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 87<br />
}<br />
public boolean hat_geburtstag( int datum ) {<br />
return personPart.hat_geburtstag( datum );<br />
}<br />
public int getMatNr() { return matNr; }<br />
public int getSemester() { return semester; }<br />
public class Test {<br />
public static void main( String[] argv ) {<br />
int i;<br />
Person[] pf = new Person[3];<br />
pf[0] = new PersonCl( "Meyer", 19631007 );<br />
pf[1] = new StudentCl( "Schmidt", 19641223, 6758475, 5 );<br />
pf[2] = new StudentCl( "Planck", 18580423, 3454545, 47 );<br />
}<br />
}<br />
for( i = 0; i
2.1 Konzepte objektorientierter Programmierung 88<br />
2. Vererbung ohne Subtyping:<br />
Vererbung wird teilweise zur Codewiederverwendung<br />
benutzt, ohne eine ist-ein-Beziehung zwischen Subklassenund<br />
Superklassenobjekt zu etablieren (problematisches<br />
Vorgehen).<br />
Beispiel(Vererbung ohne Subtyping):<br />
public class List {<br />
public boolean contains( int i ) { return true; }<br />
public int getFirst( ) { return 0;}<br />
public void addFirst( int i ) { }<br />
public void removeFirst() { }<br />
public void remove( int i ) { }<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 89<br />
public class Set extends List {<br />
public int getSome() { return getFirst(); }<br />
public void add( int i ) {<br />
addFirst(i);<br />
}<br />
public void addFirst( int i ) {<br />
if( !contains(i) ) super.addFirst(i);<br />
}<br />
public void removeFirst() {<br />
System.out.println("Should not be used!!");<br />
}<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 90<br />
Objektorientierte Sicht auf Prozeduren und<br />
Klassen<br />
1. Zeiger auf Prozeduren lassen sich über Objekte realisieren:<br />
◦ definiere Schnittstellentyp mit einer Methode, deren Signatur der<br />
Prozedursignatur entspricht<br />
◦ für jede Prozedur p implementiere den Schnittstellentyp durch<br />
Klasse KP.<br />
◦ statt dem Zeiger auf die Prozedur p übergebe KP-Objekt op<br />
◦ Aufruf: op.p(...)<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 91<br />
Beispiel(Zeiger auf Prozeduren):<br />
Call-back-Prozeduren werden im AWT durch sogenannte<br />
Listener-Objekte realisiert, die eine Listener-Schnittstelle<br />
implementieren. Besitzt diese Schnittstelle genau eine<br />
Methode, ergibt sich ein Verhalten wie bei<br />
Prozedurzeigern.<br />
public interface ActionListener extends EventListener {<br />
/**<br />
* Invoked when an action occurs.<br />
*/<br />
public void actionPerformed(ActionEvent e);<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 92<br />
2. Analogie zwischen Prozeduren und Klassen:<br />
◦ beides sind statische Programmelemente, von denen zur Laufzeit<br />
Instanzen gebildet werden (Prozedurinkarnationen, Objekte)<br />
◦ Prozedurinkarnationen und Objekte besitzen Identität, Zustand und<br />
Lebensdauer.<br />
◦ Besitzt ein Objekt einen eigenen Thread und kann es sein Ende selbst<br />
bestimmen (aktives Objekt), verhält es sich wie eine<br />
Prozedurinkarnation, die während der Laufzeit von ”außen”<br />
angesprochen werden kann.<br />
BETA nutzt diese Analogie und vereinheitlicht Klassen und<br />
Methoden zu sogenannten Pattern.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 93<br />
3. Klassen als Objekte:<br />
Betrachtet man eine Klasse als Objekt, muss sie für ihre<br />
Aufgaben Methoden bereitstellen:<br />
◦ Erzeugen von Objekten<br />
◦ Auskunft über ihre Eigenschaften geben<br />
◦ Konstruktion neuer Klassen ermöglichen<br />
Beispiel(Introspektion in Java):<br />
import java.lang.reflect.*;<br />
public class Inspektor {<br />
public static void main(String[] ss) {<br />
try{<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.1 Konzepte objektorientierter Programmierung 94<br />
}<br />
}<br />
Class klasse = Class.forName( ss[0] );<br />
Method[] methoden = klasse.getMethods();<br />
for( int i = 0; i < methoden.length; i++ ){<br />
Method m = methoden[i];<br />
Class retType = m.getReturnType();<br />
String methName = m.getName();<br />
Class[] parTypes = m.getParameterTypes();<br />
System.out.print(retType.getName()+" "+methName+"(");<br />
for( int j = 0; j < parTypes.length; j++ ){<br />
if( j > 0 ) System.out.print(", ");<br />
System.out.print( parTypes[j].getName() );<br />
}<br />
System.out.println( ");" );<br />
}<br />
} catch( ClassNotFoundException e ) {<br />
System.out.println("Klasse "+ss[0]+" nicht gefunden");<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 95<br />
2.2 Semantik objektorientierter Sprachen<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
2.2.1 Einführung
2.2 Semantik objektorientierter Sprachen 96<br />
Anwendungen von Semantikspezifikationen:<br />
• Sprachspezifikation<br />
• Hilfe beim Sprachentwurf<br />
• Grundlage zum Beweis von Spracheigenschaften<br />
• Grundlage zum Beweis von Programmeigenschaften<br />
• Klärung bei der Programmierung<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 97<br />
Beispiel(Binden von Attributen):<br />
class A {<br />
int i=1;<br />
int m() { return i*100; }<br />
int n() { return i+m(); }<br />
}<br />
class B extends A {<br />
int i=10;<br />
int m() { return i*1000; }<br />
int p() { return n(); }<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 98<br />
public class Bindung {<br />
int m() {<br />
A[] ar = { new A(), new B() };<br />
return ar[0].i + ar[0].m() + ar[1].i + ar[1].m();<br />
}<br />
}<br />
public static void main(String[] argv) {<br />
A a = new B();<br />
System.out.println(new A().m()); /* 1 */<br />
System.out.println(a.m()); /* 2 */<br />
System.out.println(a.i); /* 3 */<br />
System.out.println(new B().p()); /* 4 */<br />
System.out.println(new Bindung().m()); /* 5 */<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 99<br />
Beispiel(Binden von super-Aufrufen):<br />
class C1 {<br />
void m(){<br />
System.out.println("in C1");<br />
}<br />
}<br />
class C2 extends C1 {<br />
void m(){<br />
System.out.println("in C2");<br />
super.m();<br />
}<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 100<br />
class C3 extends C2 { }<br />
class C4 extends C3 {<br />
void m(){<br />
System.out.println("in C4");<br />
super.m();<br />
}<br />
}<br />
public class Super {<br />
public static void main( String argv[] ){<br />
C1 c1 = new C4();<br />
c1.m();<br />
}<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 101<br />
2.2.2 Operationelle Semantik einer Untersprache von<br />
Java<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 102<br />
Abstrakte Syntax von Java-KE<br />
Package = pack(PackId ImportList TypeDeclList)<br />
ImportList = list of PackId<br />
TypeDeclList = list of TypeDecl<br />
TypeDecl = ClassDecl(CTypeId CTypeId ITypeIdList ClassBody)<br />
| InterfaceDecl(ITypeId ITypeIdList InterfaceBody)<br />
ClassBody = list of MemberDecl<br />
MemberDecl = FieldDecl(Type FieldId)<br />
| MethodDecl(MethodSig Statement)<br />
InterfaceBody = list of MethodSig<br />
MethodSig = Sig(Type MethodId Type)<br />
Type = booleanT () | intT () | nullT () | ct(CTypeId) | it(ITypeId)<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 103<br />
Statement = block(Type VarId Statement)<br />
| fread(VarId VarId FieldId)<br />
| fwrite(VarId FieldId VarId)<br />
| cassign(VarId Type Exp)<br />
| new(VarId CTypeId)<br />
| seq(Statement Statement)<br />
| if (Exp Statement Statement)<br />
| while(Exp Statement)<br />
| catch(Statement CTypeId VarId Statement)<br />
//try − body CTypeId = NullPExc or CastExc<br />
| invoc(VarId VarId MethodId Exp)<br />
| call(VarId CTypeId MethodId Exp)<br />
Exp = ic(Int) | bc(Bool) | null() | id(VarId)<br />
| unary(UnOp Exp) | binary(Exp BinOp Exp)<br />
PackId, FieldId, MethodId, CTypeId, ITypeId und VarId sind einfache<br />
Sorten.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 104<br />
Kontextabhängige Syntax von Java-KE<br />
Kontextbedingungen:<br />
1. Kontextbedingungen wie in Java. Ausnahme: Die<br />
Methode main zum Starten eines Programmes hat genau<br />
einen Parameter des Typs int und liefert einen Wert des<br />
Typs int.<br />
2. Programme haben eine Klasse Object mit mindestens<br />
einer Methode (in diesem Fall ist der zweite Parameter von<br />
ClassDecl auch Object, ohne dass dies den Schluss<br />
erlaube, Object sei ein echter Subtyp von sich selbst).<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 105<br />
3. Programme haben die Klassen CastExc und NullPExc.<br />
4. Der CTypeId in einer call Anweisung muss die<br />
Superklasse bezeichnen, in der die Supermethode definiert<br />
ist.<br />
5. Deklarierte Variablen dürfen nicht res oder exc genannt<br />
werden. res ist implizit deklariert und sichtbar in jeder<br />
Anweisung, wie auch par und this.<br />
exc darf in Anweisungen nicht verwendet werden.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 106<br />
6. FieldIds sind eindeutig, d.h. Attribute in verschiedenen<br />
Klassen müssen unterschiedlich benannt werden (z.B.<br />
durch Voranstellung des CTypeId der enthaltenden<br />
Klasse).<br />
7. Typnamen müssen eindeutig sein (zum Beispiel darf ein<br />
Paket P nur Pakete importieren, deren Typnamen sich von<br />
denen, die in P deklariert sind, unterscheiden).<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 107<br />
Definition(Programmbereich in Java-KE):<br />
Jedes Paket P definiert einen Programmbereich, der<br />
• P enthält sowie<br />
• alle direkt oder indirekt von P importierten Pakete.<br />
Bemerkung:<br />
Für jedes Programmelement (Deklaration, Anweisung) gibt<br />
es einen minimalen Programmbereich, in dem es enthalten<br />
ist.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 108<br />
Statische Semantik<br />
Die statische Semantik liefert die Begriffe, um die<br />
Ausführungszustände von Programmen zu beschreiben.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 109<br />
: T ype × T ype → Bool // Subtyprelation<br />
≺ : T ype × T ype → Bool // echte Subtyprelation<br />
ObjId : eine passende Menge von Objektbezeichnern<br />
InstVar : eine passende Menge von typisierten Instanzvariablen<br />
DeclMethId : eindeutige Namen für die implementierten Methoden<br />
VirtMethId : eindeutige Namen für die virtuellen Methoden<br />
ProgPart : DeclMethId | VirtMethId | Statement@<br />
wobei Statement@ die Menge der Anweisungsknoten des<br />
kleinsten umgebenden Programmbereichs bezeichnet.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 110<br />
Bemerkungen:<br />
• Eine implementierte Methode ist eine Methode, deren<br />
Rumpf in einer Klasse deklariert ist.<br />
• Eine virtuelle Methode ist eine Methode, die in einem Typ<br />
deklariert ist.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 111<br />
Die Funktion vis : ProgPart → POW (VarId) liefert für<br />
jeden Programmteil pp die Menge der sichtbaren VarIds.<br />
Für Anweisungen c gilt: vis(c) enthält res, exc, this, par<br />
und die deklarierten lokalen Variablen.<br />
Für Methodenabstraktionen m gilt:<br />
vis(m) = {this, par, exc}<br />
Die Funktion typs : PackId → POW (Type) liefert für jedes<br />
Paket M die Menge der Typen, die in M bekannt sind.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 112<br />
Werte und Abkürzungen von Java-KE<br />
Value = b(Bool)<br />
| i(Int)<br />
| null()<br />
| ref (CTypeId ObjId)<br />
typ : Value → Type // Typ eines Wertes<br />
rtyp : ProgPart → Type<br />
// Ergebnistyp einer Methode oder Typ von res<br />
styp : InstVar → Type //Typ einer Instanzvariablen<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 113<br />
styp : VarId × ProgPart → Type<br />
// deklarierter Typ einer Variablen sichtbar in ProgPart;<br />
// styp(exc,pp)=ct(Object); ansonsten nicht determiniert<br />
impl : T ype × MethodId → DeclMethId<br />
// impl(T,m) ist nicht determiniert, wenn T keine<br />
// Implementierung einer Methode m enthält.<br />
vm : T ype × MethodId → V irtMethId<br />
// vm(T,m) ist nicht determiniert, wenn m nicht in T ist<br />
body : DeclMethId → Statement<br />
vmid : V irtMethId → MethodId<br />
. : V alue × F ieldId → InstV ar<br />
//v.f liefert die Instanzvariable f des Objektes v;<br />
//ansonsten nicht determiniert<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 114<br />
Modellierung des Objektspeichers<br />
〈 := 〉 : Store × InstVar × Value → Store<br />
〈 〉 : Store × CTypeId → Store<br />
( ) : Store × InstVar → Value<br />
new : Store × CTypeId → Value<br />
alive : Store × Value → Value<br />
IV1 = IV2 ⇒ OS〈IV1 := X 〉(IV2 ) = OS(IV2 )<br />
OS〈T 〉(IV ) = OS(IV )<br />
alive(OS〈IV := Y 〉, X ) ⇔ alive(OS, X )<br />
alive(OS〈T 〉, X ) ⇔ alive(OS, X ) ∨ X = new(OS, T )<br />
alive(OS, OS(IV ))<br />
typ(new(OS, T )) = ct(T )<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 115<br />
Zustände von Variablen und Objektspeicher<br />
State : (VarId → Value) × ({$} → Store)<br />
Zustände werden üblicherweise mit S, SQ, SR bezeichnet.<br />
Die Anwendung eines Zustandes auf ein VarId v wird mit<br />
S(v) bezeichnet, auf die Speichervariable $ mit S($).<br />
Eine Änderung von S in v oder $ wird mit S[v := E] bzw.<br />
S[$ := E] bezeichnet.<br />
Sei e ein Programmausdruck der Sorte Exp. Dann<br />
bezeichnet e[S] die Auswertung von e in S.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 116<br />
Für jeden Typ wird ein initialer Wert vorausgesetzt:<br />
init : T ype → V alue<br />
typ(init(T )) T<br />
T kann ein Schnittstellentyp oder ein Basistyp sein.<br />
init(T ) kann gleich null() sein.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 117<br />
Dynamische Semantik<br />
Wir beschreiben die dynamische Semantik operationell.<br />
Um nicht auf statische Methoden zurückgreifen zu müssen,<br />
wird die Programmausführung dadurch gestartet, dass ein<br />
Objekt der Startklasse Main erzeugt wird. Die Klasse Main<br />
muss eine Methode main haben, die beim Start mit dem<br />
Eingabeargument aufgerufen wird (siehe unten). Folgende<br />
Anweisungen erläutern, was beim Programmstart passiert:<br />
int input, output;<br />
Main mainvar;<br />
mainvar = new Main();<br />
output = mainvar. main( input );<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 118<br />
Die Semantik wird durch Relationen mit folgender Signatur<br />
ausgedrückt:<br />
psem : State × P rogram × int × int × State<br />
ssem : State × Statement@ × State<br />
Die Relationen werden induktiv durch Regeln (s.u.) definiert.<br />
In den Regeln schreiben wir<br />
SP : c → SQ anstatt ssem(SP, c, SQ)<br />
SP :: p(i) → r, SQ anstatt psem(SP, p, i, r, SQ)<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 119<br />
ssem(SP, c, SQ) bedeutet, dass die Ausführung von c mit<br />
Vorzustand SP terminiert und in den Nachzustand SQ führt.<br />
SQ(exc) = null bedeutet, dass die Ausführung von c normal<br />
beendet wurde. Andernfalls endete die Ausführung abrupt<br />
mit einer Ausnahme.<br />
Bemerkung:<br />
Die Definition von ssem setzt keine Wohltypisiertheit der<br />
Zustände voraus. Solche Eigenschaften werden ausgehend<br />
von der Definition von ssem untersucht werden.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 120<br />
S[this := new(S($), Main), par := IN , exc := null, res = init(int), $ := S($)〈Main〉]<br />
: body(Main@main) → SQ<br />
S :: prog(IN ) → SQ(res), SQ<br />
S(y) = null<br />
S : x = y.a; → S[x := S($)(S(y).a)]<br />
Bemerkung:<br />
Der Gebrauch dieser Regel setzt voraus, dass S(exc) = null<br />
im Vorzustand, ansonsten würde eine Ausnahme, die nicht<br />
vorgekommen ist, im Nachzustand sichtbar sein.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 121<br />
S(y) = null<br />
S : x = y.a; → S[$ := S($)〈NullPExc〉, exc := new(S($), NullPExc)]<br />
S(x) = null<br />
S : x.a = e; → S[$ := S($)〈S(x).a := e[S]〉]<br />
S(x) = null<br />
S : x.a = e; → S[$ := S($)〈NullPExc〉, exc := new(S($), NullPExc)]<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 122<br />
typ(e[S]) T<br />
S : x = (T )e; → S[x := e[S]]<br />
typ(e[S]) T<br />
S : x = (T )e; → S[$ := S($)〈CastExc〉, exc := new(S($), CastExc)]<br />
true<br />
S : x = newT (); → S[x := new(S($), T ), $ := S($)〈T 〉]<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 123<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
S : s1 → SQ, SQ(exc) = null, SQ : s2 → SR<br />
S : s1 s2 → SR<br />
S : s1 → SQ, SQ(exc) = null<br />
S : s1 s2 → SQ<br />
e[S], S : s1 → SQ<br />
S : if (e){s1 }else{s2 } → SQ
2.2 Semantik objektorientierter Sprachen 124<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
¬e[S], S : s2 → SQ<br />
S : if (e){s1 }else{s2 } → SQ<br />
¬e[S]<br />
S : while(e){s} → S<br />
e[S], S : s → SQ, SQ(exc) = null<br />
S : while(e){s} → SQ
2.2 Semantik objektorientierter Sprachen 125<br />
e[S], S : s → SQ, SQ(exc) = null, SQ : while(e){s} → SR<br />
S : while(e){s} → SR<br />
S : s0 → SQ, SQ(exc) = null<br />
S : try{s0 }catch(T e){s1 } → SQ<br />
S : s0 → SQ, SQ(exc) = null, typ(SQ(exc)) T<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
S : try{s0 }catch(T e){s1 } → SQ
2.2 Semantik objektorientierter Sprachen 126<br />
S : s0 → SQ, SQ(exc) = null, typ(SQ(exc)) T ,<br />
SQ[e := SQ(exc), exc := null] : s1 → SR<br />
S : try{s0 }catch(T e){s1 } → SR<br />
S[v := init(T )] : s → SQ<br />
S : {T v; s} → SQ<br />
S(y) = null, typ(S(y)) styp(y ′ , x = y.m(e); ), DMI = impl(typ(S(y)), m),<br />
S[this := S(y), par := e[S], res := init(rtyp(DMI ))] : body(DMI ) → SQ<br />
S : x = y.m(e); → S[x := SQ(res), $ := SQ($), exc := SQ(exc)]<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 127<br />
S(y) = null<br />
S : x = y.m(e); → S[$ := S($)〈NullPExc〉, exc := new(S($), NullPExc)]<br />
S[par := e[S], res := init(rtyp(impl(T , m))] : body(impl(T , m)) → SQ<br />
S : x = superT.m(e); → S[x := SQ(res), $ := SQ($), exc := SQ(exc)]<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 128<br />
Ausführung mit wohltypisierten Zuständen<br />
Argumente, warum ssem nicht von vornherein für<br />
wohltypisierte Zustände definiert wurde:<br />
• Ein Zustand ist nur im Kontext einer Anweisung<br />
wohltypisiert; deswegen wird die Quantifikation über<br />
Zustände problematisch, wenn versucht wird, Zustände<br />
typkorrekt zu machen.<br />
• Regeln auf einfache Art formulieren und dann<br />
Eigenschaften über sie beweisen<br />
• Typsicherheit als Eigenschaft beweisbar<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 129<br />
wts : Store → Bool<br />
wts(OS) ⇔ ALL InstVar IV : typ(OS(IV )) styp(IV )<br />
wt, wtp, wtr : State × ProgPart → Bool<br />
wt(S, pp) ⇔ S(this) = null ∧ wts(S($))∧<br />
∧ ALL VarId V : V ∈ vis(pp) ⇒ typ(S(V )) styp(V , pp)<br />
wtp(S, pp) ⇔ wt(S, pp) ∧ S(exc) = null<br />
wtr(S, pp) ⇔ wt(S, pp) ∧ typ(S(res)) rtyp(pp)<br />
wtr wird nur für den Nachzustand von Methoden benötigt.<br />
Für eine Anweisung gilt: wtr(S, c) ⇔ wt(S, c).<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 130<br />
Ausgehend von ssem wird eine semantische Relation<br />
definiert, die auch für Methodenabstraktionen gilt:<br />
sem : State × ProgPart × State<br />
sem(S, c, SQ) ⇔ wtp(S, c) ∧ ssem(S, c, SQ)<br />
sem(S, T @m, SQ) ⇔ wtp(S, T @m)∧<br />
∧ sem(S[res := init(rtyp(T @m))], body(T @m), SQ)<br />
sem(S, T : m, SQ) ⇔ wtp(S, T : m)∧<br />
∧ sem(S, impl(typ(S(this)), m), SQ)<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 131<br />
2.2.3 Zur Theorie strukturell operationeller<br />
Semantikdefinitionen<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 132<br />
Definition(big step SOS):<br />
Eine Semantikdefinition der oben demonstrierten Art nennt<br />
man<br />
• großschrittig, weil zu einer Regelanwendung im Allg. viele<br />
Ausführungsschritte gehören;<br />
• strukturell, weil sie der syntaktischen Programmstruktur<br />
folgt;<br />
• operationell, weil sie die Ausführung des Programms<br />
modelliert.<br />
(big step structural operational semantics, big step SOS)<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 133<br />
Es gibt zwei Arten, eine SOS-Spezifikation zu lesen:<br />
1. Liste von Inferenzregeln zur Ausführung von Programmen:<br />
sem(S, pp, SQ) gilt genau dann, wenn es eine endliche<br />
Herleitung für sem(S, pp, SQ) mit den Regeln gibt.<br />
2. Notationelle Kurzform für eine rekursive<br />
Prädikatdefinition: Spezifikation eines Prädikats als<br />
schwächsten Fixpunkt.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 134<br />
Beispiel(rekursive Prädikatdefinition):<br />
typ(e[S]) T<br />
ssem(S, x = (T )e; , S[x := e[S]])<br />
ssem(S, s1 , SQ), SQ(exc) = null, ssem(SQ, s2 , SR)<br />
ssem(S, s1 s2 , SR)<br />
ssem(S, c, SR) ⇔<br />
...<br />
∨ ((c hat die Form x = (T )e; ) ∧ typ(e[S]) T ∧ SR = S[x := e[S]] )<br />
...<br />
∨ ((c hat die Form s1 s2 )∧<br />
∃SQ : ssem(S, s1 , SQ) ∧ SQ(exc) = null ∧ ssem(SQ, s2 , SR)<br />
)<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 135<br />
Lemma:<br />
Java-KE ist deterministisch, d.h. ssem definiert eine partielle<br />
Funktion, und es gilt für alle Zustände S, SQ, SR, pp:<br />
ssem(S, pp, SQ) und ssem(S, pp, SR) impliziert SQ = SR<br />
Beweisskizze:<br />
Wir zeigen per Induktion nach n:<br />
Sind zwei Herleitungsbäume HQ, HR mit ssem(S, pp, SQ)<br />
bzw. ssem(S, pp, SR) als Wurzeln gegeben, tiefe(HQ) ≤ n<br />
und tiefe(HR) ≤ n, dann gilt HQ = HR und insbesondere<br />
SQ = SR.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 136<br />
Induktionsanfang n = 1:<br />
Bei gegebenem S und pp gibt es genau eine Instanz der<br />
Regeln ohne Vorkommen von sem in dem Antecedent.<br />
Induktionsschritt n → n + 1:<br />
Seien HQ und HR zwei Herleitungsbäume mit<br />
ssem(S, pp, SQ) bzw. ssem(S, pp, SR) als Wurzeln und<br />
o.E.d.A. tiefe(HQ) = n + 1 und tiefe(HR) ≤ n + 1 .<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 137<br />
Fall 1:<br />
S und pp bestimmen die letzte angewendete Regel r in HR<br />
und HQ.<br />
1.1: Der Antecedent von r enthält maximal ein rekursives<br />
Vorkommen von ssem. Dann bestimmen S und pp den<br />
Vorzustand S0 und den Programmteil pp0 für dieses<br />
Vorkommen (in allen Regeln nur funktionale<br />
Abhängigkeiten).<br />
Nach Induktionsvoraussetzung muss dann der Nachzustand<br />
des zugehörigen Astes der beiden Herleitungen gleich sein.<br />
Damit ist aber auch SQ = SR.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 138<br />
1.2: Der Antecedent von r enthält zwei rekursive<br />
Vorkommen von ssem. Dann bestimmen S und pp den<br />
Vorzustand S0 und den Programmteil pp0 für das erste<br />
Vorkommen (in allen Regeln nur funktionale<br />
Abhängigkeiten).<br />
Nach Induktionsvoraussetzung muss dann der Nachzustand<br />
des zugehörigen Astes der beiden Herleitungen gleich sein.<br />
Damit ist der Vorzustand für das zweite rekursive<br />
Vorkommen gleich. Die Induktionsvoraussetzung liefert<br />
wieder, dass die Nachzustände gleich sind und damit auch<br />
SQ = SR. Entsprechend für weitere rekursive Vorkommen.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 139<br />
Fall 2:<br />
Gemäß S und pp kommen zwei oder drei Regeln als letzte<br />
Regeln in HR und HQ in Frage. In allen diesen Regeln ist der<br />
erste Antecedent gleich und – wie unter Fall 1 erläutert –<br />
ergibt sich gemäß Induktionsvoraussetzung ein gleicher<br />
Nachzustand zum ersten Antecedenten. Entsprechend<br />
angewendet auf die weiteren Antecedenten ergibt sich, dass<br />
die letzten Regeln in HR und HQ gleich sein müssen und<br />
SR=SQ.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.2 Semantik objektorientierter Sprachen 140<br />
Bemerkung:<br />
Der Beweis des obigen Lemmas benutzt die<br />
Inferenzregel-Interpretation der Semantik. Bei der<br />
Fixpunktinterpretation müsste eine andere Beweistechnik<br />
verwendet werden.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.3 Eigenschaften objektorientierter Programme 141<br />
2.3 Eigenschaften objektorientierter<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
Programme
2.3 Eigenschaften objektorientierter Programme 142<br />
Übersicht<br />
Dieser Abschnitt gibt eine kurze<br />
Programmeigenschaften.<br />
Wir unterscheiden:<br />
• Zusicherungen<br />
• Anweisungsspezifikationen<br />
• Ablaufeigenschaften<br />
• Schnittstelleneigenschaften<br />
• weitere Eigenschaften<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
Übersicht über relevante
2.3 Eigenschaften objektorientierter Programme 143<br />
Definition(Programmvariable):<br />
Eine Programmvariable ist ein lokale Variable, ein<br />
Parameter, eine Instanzvariable oder eine Klassenvariable.<br />
Programmvariablen speichern Werte.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.3 Eigenschaften objektorientierter Programme 144<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
2.3.1 Zusicherungen
2.3 Eigenschaften objektorientierter Programme 145<br />
Sei S eine Programmstelle in einem Programm P.<br />
Eine Zusicherung an der Stelle S ist eine Eigenschaft, die<br />
immer gelten soll, wenn die Ausführung S erreicht.<br />
Zusicherungen lassen sich mittels eines Ausdrucks oder einer<br />
Formel über den an S sichtbaren Größen spezifizieren.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.3 Eigenschaften objektorientierter Programme 146<br />
Beispiel(Zusicherungen):<br />
1. Einfache Eigenschaft:<br />
...<br />
C cobj = new C(...);<br />
assert cobj.x != null ;<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.3 Eigenschaften objektorientierter Programme 147<br />
2. Schleifeninvariante:<br />
public static int isqrt( int x ){<br />
int count = 0, sum = 1;<br />
while (sum
2.3 Eigenschaften objektorientierter Programme 148<br />
3. Komplexere Eigenschaft im Kontext vom AWT:<br />
...<br />
Container c;<br />
Button b;<br />
...<br />
c.remove(b);<br />
assert !EX Container cex: !EX int i:<br />
cex.getComponents()[i] == b;<br />
...<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.3 Eigenschaften objektorientierter Programme 149<br />
Bemerkung:<br />
• Zusicherungen können Aussagen über den Zustand von<br />
Programmvariablen machen.<br />
• Werden Java-Ausdrücke zur Spezifikation verwendet,<br />
sollten diese seiteneffektfrei sein.<br />
• Zusicherungen können verwendet werden, um<br />
Vorbedingungen von Methoden zu beschreiben.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.3 Eigenschaften objektorientierter Programme 150<br />
2.3.2 Anweisungsspezifikationen<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.3 Eigenschaften objektorientierter Programme 151<br />
Anweisungsspezifikationen beschreiben das Verhalten einer<br />
Anweisung, Prozedur oder Methode (im Folgenden nur für<br />
Anweisungen formuliert).<br />
Wir unterscheiden:<br />
• Vor- und Nachbedingungsspezifikationen<br />
• Ereignisspezifikation<br />
• Spezifikation von Terminierung<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.3 Eigenschaften objektorientierter Programme 152<br />
Vor- und Nachbedingungsspezifikationen<br />
Im Unterschied zu Zusicherungen beziehen sich Vor- und<br />
Nachbedingungsspezifikationen auf zwei Zustände.<br />
Beispiel(Vor- und Nachbedingungsspezifikationen):<br />
1. Ohne Verwendung der Variablenwerte des Vorzustands<br />
pre x>=0 && count==0 && sum == 1<br />
while (sum
2.3 Eigenschaften objektorientierter Programme 153<br />
2. Mit Verwendung der Variablenwerte des Vorzustands<br />
pre a == X<br />
post a == X + n;<br />
void incrA ( int n ) {<br />
a += n;<br />
}<br />
Alternativ:<br />
pre true<br />
post a == \old(a) + n;<br />
void incrA ( int n ) {<br />
a += n;<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.3 Eigenschaften objektorientierter Programme 154<br />
Ereignisspezifikationen<br />
Ereignisspezifikationen machen Aussagen über Ereignisse, die<br />
bei der Ausführung von Anweisungen auftreten oder nicht<br />
auftreten dürfen.<br />
Typische Ereignisse beziehen sich auf:<br />
• Auftreten von Ausnahmen<br />
• Aufrufe von Methoden<br />
• Modifikation von Variablen<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.3 Eigenschaften objektorientierter Programme 155<br />
Beispiel(Ereignisspezifikationen):<br />
modifiable this.width, this.height ;<br />
public void resize(int width, int height) {<br />
...<br />
}<br />
Bedeutung:<br />
Aufrufe von resize haben nur die Erlaubnis, die<br />
Instanzvariablen width, height des Zielobjektes zu ändern.<br />
Andere Instanzvariablen dürfen nicht modifiziert werden.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.3 Eigenschaften objektorientierter Programme 156<br />
Bemerkung:<br />
Bei Abschwächung der Bedeutung lassen sich<br />
Ereignisspezifikationen durch Vor- und<br />
Nachbedingungsspezifikationen ersetzen:<br />
pre $(IV) = X ;<br />
post $(IV) = X \/ IV = this.width \/ IV = this.height ;<br />
public void resize(int width, int height) {<br />
...<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.3 Eigenschaften objektorientierter Programme 157<br />
Spezifikation von Terminierung<br />
Terminierung wird meist implizit im Zusammenhang mit<br />
Vorbedingungen spezifiziert. Eine Spezifikation<br />
pre <br />
post <br />
<br />
bedeutet dann, wenn die Vorbedingung erfüllt ist, terminiert<br />
die Anweisung.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.3 Eigenschaften objektorientierter Programme 158<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
2.3.3 Ablaufeigenschaften
2.3 Eigenschaften objektorientierter Programme 159<br />
Die Sequenz der Zustände, die sich bei der Ausführung eines<br />
Programms ergeben, nennen wir einen Ablauf. Dabei können<br />
die Schritte von Zustand zu Zustand mehr oder weniger<br />
umfangreich sein.<br />
Ggf. kann ein Ablauf auch mit zusätzlicher Information<br />
versehen sein (z.B. Aufruf und Verlassen von Methode).<br />
Eigenschaften, die sich auf Abläufe beziehen, nennen wir<br />
Ablaufeigenschaften.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.3 Eigenschaften objektorientierter Programme 160<br />
Wir unterscheiden:<br />
• Invarianten<br />
• zustandsübergreifende Eigenschaften<br />
• temporale Eigenschaften<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.3 Eigenschaften objektorientierter Programme 161<br />
Invarianten<br />
Invarianten sind Eigenschaften, die grundsätzlich in allen<br />
Zuständen gelten sollen.<br />
Beispiel(Invarianten):<br />
1. Typinvarianten :<br />
Das Typsystem garantiert üblicherweise, dass in allen<br />
Zuständen gilt:<br />
Speichert eine Programmvariable V einen Wert W, dann ist<br />
der Typ von W ein Subtyp des (statischen) Typs von V.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.3 Eigenschaften objektorientierter Programme 162<br />
2. Klasseninvarianten :<br />
Klassen können mit Klasseninvarianten annotiert werden.<br />
Die spezifizierte Eigenschaft sollte im Wesentlichen in allen<br />
Ausführungszuständen gelten, in denen das betreffende<br />
Objekt lebt. (Mögliche Ausnahmen sind z.B. Zustände<br />
innerhalb der Ausführungszustände privater Methoden.)<br />
Beispiel(Klasseninvarianten):<br />
class C {<br />
//@ invariant myobject != null;<br />
SomeObject myobject;<br />
...<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.3 Eigenschaften objektorientierter Programme 163<br />
3. Klassenübergreifende Invarianten :<br />
• zur Beschreibung von Objektstrukturen, die aus Objekten<br />
mehrerer Klassen bestehen<br />
• Kapselungseigenschaften, z.B. die Garantie, dass<br />
bestimmte Objekte nur von Objekten des eigenen Pakets<br />
referenziert werden<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.3 Eigenschaften objektorientierter Programme 164<br />
Zustandsübergreifende Eigenschaften<br />
Eine zustandsübergreifende Eigenschaft (engl. history<br />
property) bezieht sich auf mehrere Zustände. Wir<br />
konzentrieren uns hier auf zustandsübergreifende<br />
Eigenschaften, die sich auf zwei Zustände beziehen (binäre<br />
Eigenschaft).<br />
Eine binäre Eigenschaft E gilt in einem Ablauf A, wenn E für<br />
alle Paare (Z1, Z2) von (sichtbaren) Zuständen aus A gilt.<br />
Zustandsübergreifende Eigenschaften sind die einfachste<br />
Form, um die Entwicklungen in Abläufen zu beschreiben.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.3 Eigenschaften objektorientierter Programme 165<br />
Beispiel(Zustandsübergreifende Eigenschaften):<br />
1. Eine Variable x verändert nicht ihren Wert:<br />
constraint x == \old(x) ;<br />
oder<br />
constraint if \old(x)!= null then x == \old(x) ;<br />
2. Der Wert einer ganzzahligen Variablen nimmt nicht ab:<br />
constraint \old(x)
2.3 Eigenschaften objektorientierter Programme 166<br />
Temporale Eigenschaften<br />
Temporale Eigenschaften können sich auf beliebig viele<br />
Zustände beziehen und schließen Existenzaussagen sowie<br />
Aussagen über Teile des Ablaufs ein.<br />
Insbesondere umfassen sie: Lebendigkeitseigenschaften<br />
(etwas Gutes wird in der Zukunft passieren)<br />
Sie stellen eine Verallgemeinerung von Invarianz und<br />
zustandsübergreifenden Aussagen dar.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.3 Eigenschaften objektorientierter Programme 167<br />
Beispiel(Temporale Eigenschaften):<br />
1. Zustandsbezogene temporale Eigenschaften<br />
sometimes x != null<br />
x == 0 until a == 8<br />
2. Ereignisbezogene temporale Eigenschaften<br />
call(m) sometimes call(n)<br />
Bemerkung:<br />
Temporale Eigenschaften sind insbesondere im<br />
Zusammenhang mit parallelen Programmen wichtig.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.3 Eigenschaften objektorientierter Programme 168<br />
2.3.4 Schnittstelleneigenschaften<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.3 Eigenschaften objektorientierter Programme 169<br />
Schnittstelleneigenschaften unterscheiden sich von anderen<br />
Programmeigenschaften dadurch, dass sie sich nicht oder<br />
nur teilweise auf die Implementierung beziehen dürfen.<br />
Schnittstelleneigenschaften benötigen Abstraktion.<br />
Beispiel(Schnittstelleneigenschaften):<br />
package org.jmlspecs.samples.stacks;<br />
//@ model import org.jmlspecs.models.*;<br />
public abstract class UnboundedStack {<br />
/*@ public model JMLObjectSequence theStack<br />
@ initially theStack != null && theStack.isEmpty();<br />
@*/<br />
//@ public invariant theStack != null;<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.3 Eigenschaften objektorientierter Programme 170<br />
/*@ public normal_behavior<br />
@ requires !theStack.isEmpty();<br />
@ modifies theStack;<br />
@ ensures theStack.equals(\old(theStack.trailer()));<br />
@*/<br />
public abstract void pop( );<br />
/*@ public normal_behavior<br />
@ modifies theStack;<br />
@ ensures theStack.equals(\old(theStack.insertFront(x)));<br />
@*/<br />
public abstract void push(Object x);<br />
/*@ public normal_behavior<br />
@ requires !theStack.isEmpty();<br />
@ ensures \result == theStack.first();<br />
@*/<br />
public abstract Object top( );<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.3 Eigenschaften objektorientierter Programme 171<br />
Bemerkung: Techniken zur Spezifikation der abstrakten<br />
Datenstruktur, die der Schnittstellenspezifikation zugrunde<br />
liegt:<br />
• seiteneffektfreies, auf Verständnis optimiertes<br />
Java-Programm<br />
• mathematische Modellierung<br />
• algebraische oder logische Theorie<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.3 Eigenschaften objektorientierter Programme 172<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
2.3.5 Weitere Eigenschaften
2.3 Eigenschaften objektorientierter Programme 173<br />
• nicht funktionale Eigenschaften:<br />
◦ Effizienz<br />
◦ Portabilität<br />
◦ Skalierbarkeit<br />
◦ ...<br />
• Kapselungseigenschaften:<br />
◦ Kapselungsbereiche<br />
◦ Sicherheitsgarantien<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 174<br />
2.4 Modularität und Kapselung<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 175<br />
2.4.1 Modularität und modulare Spezifikation<br />
2.4.2 Kapselung und Schnittstellenbildung<br />
2.4.3 Realisieren von Kapselung<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 176<br />
2.4.1 Modularität und modulare Spezifikation<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 177<br />
Definition(Modulare Programmierung):<br />
Modulare Programmierung bedeutet:<br />
1. Ergebnis der Programmierung sind Programmmodule,<br />
nicht notwendig vollständige Programme.<br />
2. Die Implementierung eines Moduls kann andere Module<br />
benutzen: Deren Implementierung muss nicht notwendig<br />
bekannt sein.<br />
3. Der Anwendungskontext eines Moduls ist zur<br />
Entwicklungszeit im Allg. nicht bekannt.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 178<br />
Definition(Modulare Spezifikation):<br />
Eine Spezifikationstechnik für modulare Programme heißt<br />
modular, wenn sie folgende Eigenschaften besitzt:<br />
1. Sie ermöglicht es, Modulschnittstellen zu spezifizieren.<br />
2. Die Spezifikation S(M) eines Moduls M reicht aus, um M<br />
benutzen zu können, d.h.:<br />
◦ S(M) beschreibt die relevanten Eigenschaften von M.<br />
◦ S(M) reicht aus, um die Korrektheit von Modulen zu zeigen, die M<br />
benutzen.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 179<br />
3. Die Korrektheit einer Modulspezifikation S(M) lässt sich<br />
ohne Kenntnis möglicher Anwendungskontexte von M<br />
zeigen, d.h. mit Kenntnis:<br />
◦ der Spezifikationen verwendeter Module<br />
◦ der Implementierung von M.<br />
4. Die Korrektheit einer Modulspezifikation S(M) bleibt in<br />
jedem zulässigen Anwendungskontext erhalten.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 180<br />
Beispiel(Problematik modularer Spezifikationen):<br />
package somepack;<br />
public class C {<br />
protected int a = 7;<br />
//@ ensures \result >= 7;<br />
public int getA() { return a; }<br />
}<br />
Betrachte ein Modul M, das Objekte der Klasse C als<br />
Parameter bekommt:<br />
• Der Spezifikation entsprechend kann man davon ausgehen,<br />
dass getA immer eine Zahl größer oder gleich 7 liefert.<br />
• Diese Eigenschaft kann bewiesen und in Beweisen<br />
verwendet werden.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 181<br />
Erweiterung von C:<br />
package someotherpack;<br />
import somepack.*<br />
public class D extends C {<br />
public void decrA() { a--; }<br />
}<br />
Nun kann es passieren, dass Modul M statt eines C-Objekts<br />
ein D-Objekt erhält. Für D-Objekte gilt aber nicht die<br />
Eigenschaft von getA, und die Beweise, die sich auf die<br />
Korrektheit von M abgestützt haben, werden ungültig.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 182<br />
Lösungsansatz:<br />
• klare Schnittstellenbildung und Kapselung<br />
• Spezifikation der relevanten Eigenschaften<br />
• Subtypen müssen Spezifikation der Supertypen erfüllen<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 183<br />
2.4.2 Kapselung und Schnittstellenbildung<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 184<br />
Information Hiding und Kapselung (engl. encapsulation)<br />
werden häufig synonym bebraucht. In unserer Begriffsbildung<br />
ist Kapselung schärfer gefasst als Information Hiding.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 185<br />
Definition(Information Hiding):<br />
Information Hiding ist eine Technik, um die Abhängigkeiten<br />
zwischen Klassen und Paketen zu reduzieren:<br />
• Der Anbieter stellt nur die Information (öffentlich) zur<br />
Verfügung, die für die Benutzung notwendig ist.<br />
• Der Benutzer nutzt nur die öffentliche Information.<br />
Dementsprechend bezieht sich Information Hiding vorrangig<br />
auf Software, also statische Aspekte.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 186<br />
Bemerkung:<br />
• In der OO-Programmierung gibt es zwei Arten von<br />
Benutzung:<br />
◦ Vererbungsnutzung<br />
◦ Anwendungsnutzung<br />
• Information Hiding ermöglicht:<br />
◦ konsistente Namensänderungen in versteckten Programmteilen<br />
(unkritisch);<br />
◦ Veränderungen an versteckten Implementierungsteilen, soweit sie<br />
keine Auswirkungen auf die öffentliche Funktionalität haben<br />
(kritisch).<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 187<br />
Beispiel(Information Hiding):<br />
public class MyList {<br />
private int leng;<br />
private LinkedList theList;<br />
}<br />
public int length() { return leng; }<br />
...<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 188<br />
Definition(Kapselung):<br />
Kapselung ist eine Technik zur Strukturierung des<br />
Zustandsraumes ablaufender Programme.<br />
Ziel ist es, durch Bildung von Kapseln mit klar definierten<br />
Zugriffsschnittstellen die Daten- und Strukturkonsistenz zu<br />
gewährleisten.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 189<br />
Kapseln können sein:<br />
• einzelne Objekte<br />
• zusammenhängende Objekte<br />
• eine Klasse (mit allen ihren Objekten)<br />
• alle Klassen in einer Vererbungshierarchie<br />
• Pakete (mit allen Klassen und deren Objekten)<br />
• mehrere Pakete<br />
Kapselung setzt eine Festlegung der Kapselgrenzen und der<br />
Schnittstellen an den Kapselgrenzen voraus.<br />
Kapselung bezieht sich vorrangig auf dynamische Aspekte.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 190<br />
Bemerkung:<br />
• Kapselung spielt vor allem eine wichtige Rolle im<br />
Zusammenhang mit Verteilung und Parallelität.<br />
• Kapselung wird mit Mitteln des Information Hiding<br />
erreicht.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 191<br />
Beispiel(Kapseln und Schnittstellen):<br />
1. Beschränkung auf privaten Zugriff garantiert keine<br />
Kapselung von Objekten:<br />
public class Privat {<br />
private int a;<br />
private Privat nachbar;<br />
}<br />
public void incrA(){<br />
a++;<br />
nachbar.a++;<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 192<br />
2. Die Java-Klasse LinkedList realisiert Kapseln mit einem<br />
LinkedList-Objekt und ggf. mehreren ListIterator-Objekten<br />
an der Schnittstelle:<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 193<br />
LinkedList<br />
Entry<br />
ListIterator<br />
Entry Entry Entry<br />
Object<br />
Object<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
3<br />
0<br />
Object<br />
ListIterator<br />
2
2.4 Modularität und Kapselung 194<br />
public class LinkedList extends AbstractSequentialList<br />
implements List, Cloneable, java.io.Serializable<br />
{<br />
public LinkedList();<br />
public LinkedList(Collection c);<br />
public Object getFirst(); public Object getLast();<br />
public Object removeFirst(); public Object removeLast();<br />
public void addFirst(Object o); public void addLast(Object o);<br />
public boolean contains(Object o); public int size();<br />
...<br />
public ListIterator listIterator(int index);<br />
... }<br />
public interface ListIterator extends Iterator {<br />
boolean hasNext(); Object next();<br />
boolean hasPrevious(); Object previous();<br />
int nextIndex(); int previousIndex();<br />
void remove();<br />
void set(Object o); void add(Object o); }<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 195<br />
3. Sicherheitslücke in Java 1.1.1:<br />
public final class Class ... {<br />
...<br />
private Identity[] signers;<br />
...<br />
public Identity[] getSigners() {<br />
return signers;<br />
}<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 196<br />
2.4.3 Realisieren von Kapselung<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 197<br />
Programmiersprachen stellen Sprachkonstrukte fürs<br />
Information Hiding bereit; z.B. in Java:<br />
• Zugriffsrechte: public, default, protected, private<br />
• Einschränkung der Vererbung: final<br />
• Innere Klassen<br />
Damit lässt sich Kapselung realisieren. Eine direkte<br />
Unterstützung von Kapselung durch Sprachen gibt es nicht.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 198<br />
Beispiel(Kapselung):<br />
Die Klasse LinkedList implementiert Kapseln (s.o.) und<br />
schließt darin die Repräsentationsobjekte vom Typ Entry ein.<br />
Sie garantiert die folgenden Eigenschaften:<br />
a) Zugriff ist nur über LinkedList- und ListIterator-Objekte<br />
möglich.<br />
b) Benutzer besitzen keine Referenz auf Entry-Objekte.<br />
c) Zwei Kapseln haben keine Objekte gemeinsam.<br />
d) Die Eigenschaften bleiben bei Vererbung erhalten.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 199<br />
Realisierung:<br />
• Klasse Entry und Attribute mit Entry-Referenzen sind nur<br />
privat zugreifbar.<br />
• Klasse, die die Listeniteratoren implementiert, ist privat;<br />
deshalb lassen sich Iteratoren von außen nur über eine<br />
Methode von LinkedList-Objekten erzeugen.<br />
• Methoden der Schnittstellenobjekte geben keine<br />
Referenzen auf Repräsentationsobjekte heraus.<br />
Repräsentationsobjekte können nicht von außen<br />
eingeschleust werden.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 200<br />
Diskussion anhand der Implementierung:<br />
public class LinkedList ...<br />
{<br />
private ... Entry header = new Entry(null, null, null);<br />
private ... int size = 0;<br />
public LinkedList() { ... }<br />
... // public methods<br />
private Entry entry(int index) { ... }<br />
public ListIterator listIterator(int index) {<br />
return new ListItr(index);<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
}<br />
2.4 Modularität und Kapselung 201<br />
private class ListItr implements ListIterator {<br />
private Entry lastReturned = header;<br />
private Entry next;<br />
private int nextIndex;<br />
...<br />
}<br />
private static class Entry {<br />
Object element;<br />
Entry next;<br />
Entry previous;<br />
...<br />
}<br />
private Entry addBefore(Object o, Entry e) { ... }<br />
private void remove(Entry e) { ... }<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
2.4 Modularität und Kapselung 202<br />
Lesen Sie zu 2.4:<br />
A. Poetzsch-Heffter:<br />
Konzepte objektorientierter Programmierung,<br />
Springer-Verlag, 2000;<br />
Abschnitt 3.3, S. 157-171.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3. Techniken zum Prüfen<br />
objektorientierter Programme
3. Techniken zum Prüfen objektorientierter<br />
3.1 Einführung<br />
Programme<br />
3.1.1 Typinformation und ihre statische und dynamische<br />
Prüfung<br />
3.1.2 Typsicherheit<br />
3.2 Parametrische Typsysteme und Virtuelle Klassen<br />
3.3 Typsysteme zur Strukturierung von Objektgeflechten<br />
3.4 Erweiterte statische Prüfung<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
204
3.1 Einführung 205<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
3.1 Einführung
3.1 Einführung 206<br />
Ein Typ beschreibt Eigenschaften von Werten bzw. Objekten<br />
(Beispiele: int, Object, LinkedList〈A〉).<br />
Typisierung bedeutet die Annotierung von<br />
Programmelementen mit Typen:<br />
• Ausdrücke: Jede Auswertung liefert einen Wert vom Typ<br />
des Ausdrucks.<br />
• Prozeduren/Methoden: Wenn die aktuellen Parameter den<br />
richtigen Typ haben, ist das Ergebnis vom Ergebnistyp.<br />
• Variablen: Eine Variable enthält nur Werte von ihrem Typ.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.1 Einführung 207<br />
Typisierung ist eine der erfolgreichsten Anwendungen<br />
formaler Techniken.<br />
Definition(Typsystem):<br />
Das Typsystem einer Sprache S beschreibt,<br />
• welche Typen es in S gibt,<br />
• wie Programme von S typisiert werden,<br />
• welche Bedingungen typisierte Programme erfüllen müssen<br />
(Typisierungsbedingungen).<br />
Ein Programm, das die Typisierungsbedingungen erfüllt,<br />
heißt typkorrekt.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.1 Einführung 208<br />
Definition(Typfehler):<br />
Ein Typfehler tritt auf, wenn<br />
• einer Variablen ein Wert von einem falschen Typ<br />
zugewiesen wird;<br />
• eine Operation mit aktuellen Parametern aufgerufen wird,<br />
für die sie nicht definiert ist.<br />
Ein Typisierungsfehler tritt auf, wenn ein Programm nicht<br />
typkorrekt ist.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.1 Einführung 209<br />
Definition(typsicher):<br />
Eine Sprache heißt typsicher (engl. type-safe), wenn bei<br />
Ausführung ihrer (typkorrekten) Programme keine Typfehler<br />
auftreten.<br />
Ein Typsystem heißt sicher (engl. sound), wenn es<br />
Typsicherheit garantiert.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.1 Einführung 210<br />
Bemerkung:<br />
• Es gibt Programme, die nicht typkorrekt sind, aber<br />
trotzdem nicht zu Typfehlern führen.<br />
• Bei einem sicheren Typsystem folgt Typsicherheit also aus<br />
Typkorrektheit.<br />
Literatur zur Typisierung:<br />
Kim B. Bruce: Foundations of Object-Oriented Languages.<br />
Types and Semantics. MIT Press, 2002.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.1 Einführung 211<br />
3.1.1 Typinformation und ihre statische und<br />
dynamische Prüfung<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.1 Einführung 212<br />
Bei Objekten liefert der Typ insbesondere die Information,<br />
welche Nachrichten ein Objekt versteht. Damit kann in<br />
einem typkorrekten Programm gewährleistet werden, dass zu<br />
jedem Methodenaufruf eine Methodenimplementierung<br />
existiert.<br />
Ziele der Typisierung in der OO-Programmierung:<br />
• Vermeidung von Typfehlern<br />
• Optimierung<br />
• Dokumentation<br />
• Abstraktion<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.1 Einführung 213<br />
Definition(Typprüfung):<br />
Die Typprüfung besteht aus der (statischen) Prüfung der<br />
Typisierungsbedingungen und der Prüfung von<br />
Typeigenschaften zur Laufzeit (dynamische Typprüfung).<br />
Eine typsichere Sprache heißt statisch typisiert, wenn sie<br />
keine dynamische Typprüfung vorsieht.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.1 Einführung 214<br />
Beispiel(statisch typisiert):<br />
Java ist nicht statisch typisiert, sondern verlangt dynamische<br />
Typprüfung bei:<br />
• der Typkonvertierung (casts):<br />
Object obj = "Ich neues String-Objekt";<br />
String str = (String) obj;<br />
...<br />
• Feldzugriffen:<br />
String[] strfeld = new String[2];<br />
Object[] objfeld = strfeld;<br />
objfeld[0] = new Object();<br />
int strl = strfeld[0].length();<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.1 Einführung 215<br />
Typisierungsproblematik in OO-Sprachen<br />
Damit ein Subtyp-Objekt an allen Stellen vorkommen kann,<br />
an denen ein Supertyp-Objekt erwartet wird, muss garantiert<br />
sein, dass<br />
• ein Subtyp-Objekt alle Attribute seiner Supertypen hat;<br />
• ein Subtyp-Objekt alle Methoden der Supertypen hat;<br />
• die Attribute und Methoden im Subtyp zu denen in den<br />
Supertypen typmäßig passen.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.1 Einführung 216<br />
Definition(Ko-/Kontravarianz):<br />
Sei S ein Subtyp von T.<br />
Sei TV ein Typvorkommen in T (Attribut-, Parameter-,<br />
Ergebnistyp) und SV das entsprechende Typvorkommen in S.<br />
Wir sagen:<br />
• SV und TV sind kovariant, wenn SV ein Subtyp von TV<br />
ist.<br />
• SV und TV sind kontravariant, wenn TV ein Subtyp von<br />
SV ist.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.1 Einführung 217<br />
Fakt:<br />
OO-Sprachen lassen sich nur dann statisch typisieren, wenn:<br />
• Attributtypen ko- und kontravariant, d.h. invariant sind.<br />
• Parametertypen kontravariant sind.<br />
• Ergebnistypen kovariant sind.<br />
Beispiel(Ko-/Kontravarianz):<br />
interface C1 { String a; ... }<br />
class D1 implements C1 { Object a; ... }<br />
...<br />
C1 cvar = new D1(); // initialisiert a<br />
String svar = cvar.a;<br />
// Typfehler: Kovarianz nicht gegeben<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.1 Einführung 218<br />
interface C2 { Object a; ... }<br />
class D2 implements C2 { String a; ... }<br />
...<br />
C2 cvar = new D2();<br />
cvar.a = new Object();<br />
// Typfehler: Kontravarianz nicht gegeben<br />
interface C3 { String m(); ... }<br />
class D3 implements C3 { Object m(){...} ...}<br />
...<br />
C3 cvar = new D3();<br />
String svar = cvar.m();<br />
// Typfehler: Kovarianz nicht gegeben<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.1 Einführung 219<br />
interface C4 { int m(Object p); ... }<br />
class D4 implements C4 {<br />
int m(String s){<br />
s.length();...<br />
}<br />
...<br />
}<br />
...<br />
C4 cvar = new D4();<br />
cvar.m( new Object() );<br />
// Typfehler bei Ausfuehrung von m:<br />
// Kontravarianz nicht gegeben<br />
Entsprechendes gilt für die Typen der erlaubten Ausnahmen<br />
einer Methode.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.1 Einführung 220<br />
Bemerkung:<br />
• Die Ko- und Kontravarianz sind grundlegend für das<br />
Verständnis von Typsystemen und konformer<br />
Subtypbildung in OO-Sprachen.<br />
• Java bietet ein recht inflexibles Typsystem:<br />
◦ keine echt kontravarianten Parametertypen<br />
◦ keine echt kovarianten Ergebnistypen<br />
◦ Kovarianz nur bei den erlaubten Ausnahmen<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.1 Einführung 221<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
3.1.2 Typsicherheit
3.1 Einführung 222<br />
Wir diskutieren Typsicherheit am Beispiel von Java-KE.<br />
Typsystem von Java-KE:<br />
• Typen: boolean, int, Null und ein Typ für jede deklarierte<br />
Klasse und Schnittstelle.<br />
• Subtypbeziehung wie in Java:<br />
◦ Alle Referenztypen sind Subtyp von Object<br />
◦ Jede Typdeklaration für T legt die direkten Supertypen von T fest.<br />
◦ Null ist Subtyp aller Referenztypen<br />
◦ keine Subtypbeziehung zwischen Basisdatentypen und zwischen<br />
Basisdaten- und Referenztypen.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.1 Einführung 223<br />
• Typisierung von Java-KE:<br />
◦ Deklarationen sind typisiert;<br />
◦ Ausdrücke gemäß Signatur der Operatoren, der Variablendeklaration<br />
bzw. Konstanten (null bekommt den Typ Null);<br />
◦ Anweisungsteile gemäß den Deklarationen.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.1 Einführung 224<br />
• Typisierungsbedingungen von Java-KE:<br />
◦ Eine überschreibende Methode hat die gleichen Parameter- und<br />
Ergebnistypen wie die überschriebene Methode.<br />
◦ Ausdrücke in if- und while-Anweisungen müssen vom Typ boolean sein<br />
◦ Der Zieltyp C bei einer Typkonvertierung, x=(C) e, muss ein Subtyp<br />
vom Typ von e sein.<br />
◦ Der Typ der linken Seite einer Zuweisung, x = e, muss ein Supertyp<br />
vom Typ von e sein.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.1 Einführung 225<br />
Lemma:<br />
Das Typsystem von Java-KE ist sicher. Für jede Anweisung<br />
pp und Zustände S, SQ gilt:<br />
wt(S, pp) ∧ ssem(S, pp, SQ) ⇒ wt(SQ, pp)<br />
wobei wt wie auf Folie 129 definiert ist.<br />
Beweisskizze:<br />
Seien S und pp beliebig. Der syntaktischen Interpretation<br />
der SOS von Java-KE zu Folge, gibt es einen Herleitungsbaum<br />
HQ von endlicher Tiefe für ssem(S, pp, SQ).<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.1 Einführung 226<br />
Induktion nach der Herleitungstiefe n von HQ:<br />
Induktionsanfang n=1:<br />
Fallunterscheidung über die nicht-rekursiven Regeln. Wir<br />
betrachten hier exemplarisch die 1. Regel für die Zuweisung<br />
mit Typkonvertierung. Z.z.:<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.1 Einführung 227<br />
wt(S[x := e[S]], pp) mit pp = (x = (T )e)<br />
⇔ // wg. Definition von wt<br />
S[x := e[S]](this) = null ∧ wts(S[x := e[S]]($))<br />
∧ ∀VarId V : V ∈ vis(pp)<br />
⇒ typ(S[x := e[S]](V )) styp(V , pp)<br />
⇐ // wg. x = this<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.1 Einführung 228<br />
⇐ // wg. x = this<br />
S(this) = null ∧ wts(S($)) ∧ typ(e[S]) styp(x, pp)∧<br />
∀ VarId V : V ∈ vis(pp) ⇒ typ(S(V )) styp(V , pp)<br />
⇐ // wg. typ(e[S]) T aus Antecedent der Regel,<br />
// und T styp(x, pp) aus Typisierungsbedingungen<br />
wt(S, pp)<br />
Entsprechend müssen alle anderen nicht-rekursiven<br />
Inferenzregeln untersucht werden.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.1 Einführung 229<br />
Induktionsschritt n→n+1:<br />
Fallunterscheidung über die Regeln mit ssem im Antecedent.<br />
Wir betrachten hier exemplarisch die Regel für if-then-else<br />
und nehmen e[S] an. Z.z.:<br />
wt(SQ, pp) mit pp = if (e){s1 }else{s2 }<br />
⇔ // wg. Definition von wt<br />
wt(SQ, s1 )<br />
Und das folgt wegen ssem(S, s1 , SQ) und wt(S, s1 ) aus der<br />
Induktionsvoraussetzung. Entsprechend müssen alle anderen<br />
rekursiven Inferenzregeln untersucht werden.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.1 Einführung 230<br />
Literatur zu Typsicherheit von OO-Sprachen:<br />
S. Drossopoulou, S. Eisenbach: Java is Type Safe — Probably.<br />
European Conference on Object-Oriented<br />
Programming, 1997 (LNCS 1241).<br />
T. Nipkow, D. v. Oheimb: Java light is Type-Safe — Definitely.<br />
Principles of Programming Languages, 1998.<br />
A. Igarashi, B. Pierce, P. Wadler:<br />
Featherweight Java: A Minimal Core Calculus for Java and GJ<br />
Object-Oriented Programming, Systems, Languages, and Applications,<br />
1999.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 231<br />
3.2 Parametrische Typsysteme und virtuelle<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
Klassen
3.2 Parametrische Typsysteme und virtuelle Klassen 232<br />
Reine Subtyp-Polymorphie bietet bei bestimmten wichtigen<br />
Anwendungssituationen keine ausreichende Unterstützung:<br />
• Parametrisierung von Typen<br />
• Spezialisieren verwendeter Typen in Subklassen<br />
Dieser Abschnitt erläutert Lösungen für diese Probleme.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 233<br />
3.2.1 Parametrische Typsysteme<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 234<br />
Parametrisierung von Softwarekomponenten ist ein<br />
entscheidender Weg zur Wiederverwendung.<br />
Subtyp-Polymorphie leistet dazu eine wichtigen Beitrag.<br />
Nachteile:<br />
• Spezialisierung nur entlang der Subtyp-Ordnung<br />
• Keine Parametrisierung bzgl. verwendeter Typen<br />
• Keine Einschränkung der Polymorphie<br />
Moderne OO-Sprachen kombinieren Subtyp- und<br />
parametrische Polymorphie.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 235<br />
Wir betrachten hier GJ als Beispiel einer OO-Sprache mit<br />
parametrischem Polymorphismus.<br />
Literatur:<br />
G. Bracha, M. Odersky, D. Stoutamire, P. Wadler:<br />
Making the future safe for the past: Adding Genericity to<br />
the Java Programming Language.<br />
Object-Oriented Programming, Systems, Languages, and<br />
Applications, 1998.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 236<br />
Parametrische/generische Typen<br />
Idee: Erlaube an Anwendungsstellen von Typen Typvariablen<br />
anstelle von Typen.<br />
Dadurch ergeben sich parametrisierte Klassen- und<br />
Schnittstellendeklarationen. Die Typvariablen müssen beim<br />
deklarierten Typ vereinbart werden.<br />
Beispiel(Typvariablen):<br />
class Pair {<br />
A fst;<br />
B snd;<br />
Pair(A f,B s){ ... }<br />
...<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 237<br />
Pair〈A,B〉 heißt ein parametrisierter Typ.<br />
Pair heißt Typkonstruktor.<br />
Typparameter werden bei der Objekterzeugung instanziert:<br />
Pair paarvar =<br />
new Pair (<br />
new String(), new Integer() );<br />
Ein Typ wird in GJ dargestellt durch:<br />
• einen (parameterloser) Typbezeichner,<br />
• eine Typvariable,<br />
• einen Typkonstruktor angewandt auf Typen.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 238<br />
Beispiele:<br />
• String<br />
• A, wobei A eine deklarierte Typvariable ist.<br />
• Pair〈String, Object〉<br />
• Pair〈Pair〈A,A〉, String〉<br />
Wichtigste Anwendung parametrisierter Typen sind<br />
Kollektionstypen und frei erzeugte Typen.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 239<br />
interface Collection {<br />
public void add (A x);<br />
public Iterator iterator ();<br />
}<br />
interface Iterator {<br />
public A next ();<br />
public boolean hasNext ();<br />
}<br />
class NoSuchElementException extends RuntimeException {}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 240<br />
class LinkedList implements Collection {<br />
protected class Node {<br />
A elt;<br />
Node next = null;<br />
Node (A elt) { this.elt = elt; }<br />
}<br />
protected Node head = null, tail = null;<br />
public LinkedList () {}<br />
public void add (A elt) {<br />
if (head == null) {<br />
head = new Node(elt);<br />
tail = head;<br />
} else {<br />
tail.next = new Node(elt);<br />
tail = tail.next;<br />
}<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
}<br />
3.2 Parametrische Typsysteme und virtuelle Klassen 241<br />
public Iterator iterator () {<br />
return new Iterator () {<br />
protected Node ptr = head;<br />
public boolean hasNext () {<br />
return ptr != null;<br />
}<br />
public A next () {<br />
if (ptr != null) {<br />
A elt = ptr.elt;<br />
ptr = ptr.next;<br />
return elt;<br />
} else {<br />
throw new<br />
NoSuchElementException ();<br />
}<br />
}<br />
};<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 242<br />
class Test {<br />
public static void main (String[] a) {<br />
LinkedList ys = new LinkedList();<br />
ys.add("zero");<br />
ys.add("one");<br />
String y = ys.iterator().next();<br />
}<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 243<br />
Parametrische/generische Methoden<br />
Analog zu Typdeklarationen lassen sich auch<br />
Methodendeklarationen parametrisieren.<br />
Beispiel(Parametrische Methoden):<br />
interface SomeCollection extends Collection {<br />
public A some();<br />
}<br />
class Collections {<br />
public static <br />
Pair somepair(SomeCollection xa,<br />
SomeCollection xb ) {<br />
return new Pair(xa.some(),xb.some());<br />
}<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 244<br />
Einschränkung von Typvariablen<br />
Manchmal möchte man die Instanzierung von Typvariablen<br />
auf bestimmte Typen einschränken. In GJ lassen sich solche<br />
Einschränkungen (engl. bounds) bei der Deklaration der<br />
Typvariablen angeben:<br />
〈A implements T〉<br />
〈B extends T〉<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 245<br />
Beispiel(Einschränkung von Typvariablen):<br />
interface Comparable {<br />
public int compareTo (A that);<br />
}<br />
class Byte implements Comparable {<br />
private byte value;<br />
public Byte (byte value) {<br />
this.value = value;<br />
}<br />
public byte byteValue () { return value; }<br />
public int compareTo (Byte that) {<br />
return this.value - that.value;<br />
}<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 246<br />
class Collections {<br />
public static <br />
A max (Collection xs) {<br />
Iterator xi = xs.iterator();<br />
A w = xi.next();<br />
while (xi.hasNext()) {<br />
A x = xi.next();<br />
if (w.compareTo(x) < 0) w = x;<br />
}<br />
return w;<br />
}<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 247<br />
Bemerkung:<br />
• Trotz der relativ einfachen Erweiterung des Typsystems<br />
ergeben sich bereits recht umfangreiche Typisierungsregeln.<br />
• Generische Typen und Methoden sind kanonische Beispiele<br />
für parametrische Softwarekomponenten.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 248<br />
Subtyping zwischen parametrischen Typen<br />
Auch für parametrische Typen gilt:<br />
Ein Typ ist nur dann ein Subtyp eines anderen, wenn die<br />
Subtypbeziehung explizit aus den Deklarationen oder<br />
Einschränkungen ersichtlich ist:<br />
LinkedList implements Collection<br />
SomeCollection extends Collection<br />
Byte implements Comparable<br />
<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 249<br />
Die Subtypbeziehung zwischen Typparametern überträgt sich<br />
nicht auf parametrische Typen:<br />
LinkedList LinkedList<br />
Es wird Invarianz bei den Parametern verlangt.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 250<br />
Beispiel(Subtypbeziehung):<br />
Folgendes Beispiel zeigt, warum Gleichheit bei aktuellen<br />
Typparametern verlangt wird:<br />
class Loophole {<br />
public static String loophole (Byte y) {<br />
LinkedList xs = new LinkedList();<br />
LinkedList ys = xs;<br />
// Uebersetzungsfehler<br />
ys.add(y);<br />
return xs.iterator().next();<br />
}<br />
}<br />
Anders als bei Feldern ist der Typ des Parameters zur<br />
Laufzeit nicht verfügbar. Deshalb ist eine dynamische<br />
Prüfung wie bei Feldern nicht möglich.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 251<br />
Typinferenz<br />
GJ benutzt einen Typinferenzalgorithmus, der<br />
• lokal ist, d.h. der Typ eines Ausdrucks ergibt sich nur aus<br />
den Typen der Teilausdrücke;<br />
• Ausdrücke von beliebigem Referenztyp bewältigen kann<br />
(null, leere Listen);<br />
• Subsumption beherrscht, d.h. der Typ T eines Ausdrucks<br />
kann zu jedem beliebigen Supertyp verallgemeinert werden.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 252<br />
Beispiel(Typinferenz):<br />
class ListFactory {<br />
public LinkedList empty () {<br />
return new LinkedList();<br />
}<br />
public LinkedList singleton (A x) {<br />
LinkedList xs = new LinkedList();<br />
xs.add(x);<br />
return xs;<br />
}<br />
public LinkedList doublet (A x, A y) {<br />
LinkedList xs = new LinkedList();<br />
xs.add(x);<br />
xs.add(y);<br />
return xs;<br />
}<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 253<br />
class Test {<br />
static ListFactory f = new ListFactory();<br />
public static void main (String[ ] args) {<br />
LinkedList zs = f.doublet(new Integer(1), new Float(1.0));<br />
LinkedList ys = f.singleton(null);<br />
LinkedList xs = f.empty();<br />
LinkedList err = f.doublet("abc", new Integer(1));<br />
// compile-time error<br />
}<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 254<br />
Lösungsidee:<br />
Erweitere die Typausdrücke um den Typ ’*’, der Subtyp aller<br />
Referenztypen ist. Für ’*’ wird kovariantes Subtyping auf<br />
Parameterposition akzeptiert, d.h. z.B.:<br />
LinkedList ist Subtyp von LinkedList<br />
Pair ist Subtyp von Pair<br />
Für Typsicherheit ist folgende Linearitätseinschränkung<br />
erforderlich:<br />
Eine Typvariable, die mehrfach als Ergebnistyp einer<br />
Methode vorkommt, darf nicht durch ’*’ instanziert werden.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 255<br />
Beispiel(Typinferenz):<br />
class Cell {<br />
public A value;<br />
public Cell (A v) { value = v; }<br />
public static Cell make (A x) {<br />
return new Cell(x);<br />
}<br />
}<br />
class Pair {<br />
public B fst;<br />
public C snd;<br />
public Pair (B x, C y) { fst = x; snd = y; }<br />
public static Pair duplicate (D x) {<br />
return new Pair(x,x);<br />
}<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 256<br />
class Loophole {<br />
public static String loophole (Byte y) {<br />
Pair p =<br />
Pair.duplicate(Cell.make(null));<br />
// compile-time error<br />
p.snd.value = y;<br />
return p.fst.value;<br />
}<br />
public static String permitted (String x) {<br />
Pair p =<br />
Pair.duplicate(Cell.make((String)null));<br />
p.fst.value = x;<br />
return p.snd.value;<br />
}<br />
}<br />
Nach Inferenz der Typen ist die Typprüfung einfach.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 257<br />
Realisierung von Generic Java<br />
Im Wesentlichen läßt sich GJ direkt nach Java übersetzen.<br />
Die Implementierung parametrischer Typen basiert auf:<br />
• Parameterlöschung:<br />
◦ Löschen der Typparameter<br />
◦ Verwenden von Object anstelle von Typvariablen<br />
◦ Einsetzen geeigneter Typkonvertierungen (casts)<br />
• Brückenmethoden<br />
◦ Wenn eine Subklasse eine Typvariable einer Superklasse instanziert,<br />
sind ggf. zusätzliche Methoden mit geeigneter Signatur<br />
hinzuzufügen.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 258<br />
Beispiel(Parameterlöschung und Brückenmethoden):<br />
Durch Parameterlöschung und Einführen von<br />
Brückenmethoden erhält man zu obigem Beispiel:<br />
interface Comparable {<br />
public int compareTo (Object that);<br />
}<br />
class Byte implements Comparable {<br />
private byte value;<br />
public Byte (byte value) { this.value = value; }<br />
public byte byteValue () { return value; }<br />
public int compareTo (Byte that) {<br />
return this.value - that.value;<br />
}<br />
public int compareTo (Object that) {<br />
return this.compareTo((Byte)that);<br />
}<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 259<br />
class Collections {<br />
public static Comparable max (Collection xs) {<br />
Iterator xi = xs.iterator();<br />
Comparable w = (Comparable)xi.next();<br />
while (xi.hasNext()) {<br />
Comparable x = (Comparable)xi.next();<br />
if (w.compareTo(x) < 0) w = x;<br />
}<br />
return w;<br />
}<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 260<br />
Probleme mit der erläuterten Technik treten auf, wenn<br />
Typparameter nur in Rückgabetypen vorkommen:<br />
class Interval implements Iterator {<br />
private int i, n;<br />
public Interval (int l, int u) { i=l; n=u; }<br />
public boolean hasNext () { return (i
3.2 Parametrische Typsysteme und virtuelle Klassen 261<br />
Parameterlöschung und Einführen von Brückenmethoden<br />
liefert:<br />
class Interval implements Iterator {<br />
private int i, n;<br />
public Interval (int l, int u) { i = l; n = u; }<br />
public boolean hasNext () { return (i
3.2 Parametrische Typsysteme und virtuelle Klassen 262<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
3.2.2 Virtuelle Typen
3.2 Parametrische Typsysteme und virtuelle Klassen 263<br />
Statt Parametrisierung von Typen kann Spezialisierung<br />
verwendet werden. Dies ergibt eine andere Art Generizität:<br />
class Vector {<br />
typedef ElemType as Object;<br />
void addElement( ElemType e ) { ... }<br />
ElemType elementAt( int index ) { ... }<br />
}<br />
class PointVector extends Vector{<br />
typedef ElemType as Point;<br />
}<br />
Man nennt ElemType hier einen virtuellen Typ. Virtuelle<br />
Typen können in Subklassen mit Subtypen überschrieben<br />
werden.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 264<br />
Im Folgenden betrachten wir eine Erweiterung von Java um<br />
virtuelle Typen.<br />
Literatur:<br />
Kresten Krab Thorup:<br />
Genericity in Java with Virtual Types.<br />
European Conference on Object-Oriented Programming,<br />
1997.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 265<br />
Aspekte virtueller Typen<br />
1. Unterscheidung zwischen parametrischen Typen und<br />
,,normalen“ Typen ist nicht nötig:<br />
interface IteratorOfObject {<br />
typedef A as Object;<br />
public A next ();<br />
public boolean hasNext ();<br />
}<br />
interface CollectionOfObject {<br />
typedef A as Object;<br />
typedef IteratorOfA as IteratorOfObject;<br />
public void add (A x);<br />
public IteratorOfA iterator ();<br />
}<br />
class NoSuchElementException extends RuntimeException {}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 266<br />
class LinkedListOfObject implements CollectionOfObject {<br />
// erbt die virtuellen Typen A und IteratorOfA<br />
protected class Node {<br />
A elt;<br />
Node next = null;<br />
Node (A elt) { this.elt = elt; }<br />
}<br />
protected Node head = null, tail = null;<br />
}<br />
public LinkedListOfObject () {}<br />
public void add (A elt) { ... /* wie auf Folie 240 */ }<br />
public IteratorOfA iterator () {<br />
return new IteratorOfA () {... /* wie auf Folie 241 */ };<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 267<br />
interface IteratorOfString extends IteratorOfObject {<br />
typedef A as String;<br />
}<br />
class LinkedListOfString extends LinkedListOfObject {<br />
typedef A as String;<br />
typedef IteratorOfA as IteratorOfString;<br />
}<br />
class Test {<br />
public static void main (String[] a) {<br />
LinkedListOfString ys = new LinkedListOfString();<br />
ys.add("zero");<br />
ys.add("one");<br />
String y = ys.iterator().next();<br />
}<br />
}<br />
Jede Instanzierung benötigt eigene Typdeklaration.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 268<br />
2. Subtypbeziehungen zwischen generischen Typen können<br />
deklariert werden:<br />
LinkedListOfString ist Subtyp von<br />
LinkedListOfObject; also ist folgendes Fragment<br />
typkorrekt:<br />
LinkedListOfString strl = new LinkedListOfString();<br />
LinkedListOfObject objl = strl;<br />
objl.add( new Object() ); // VirtualTypeCastException<br />
Die durch virtuelle Typen entstehende Kovarianz bei<br />
Methodenparametern wird durch dynamische Typprüfung<br />
abgefangen.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 269<br />
3. Rekursive Typen und Zusammenhang mit Vererbung<br />
lassen sich besser realisieren.<br />
a) Verschränkte Rekursion am Beispiel des<br />
Observer-Musters:<br />
interface Observer {<br />
typedef SType as Subject;<br />
typedef EventType as Object;<br />
void notify (SType subj, EventType e);<br />
}<br />
class Subject {<br />
typedef OType as Observer;<br />
typedef EventType as Object;<br />
OType observers[];<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
}<br />
3.2 Parametrische Typsysteme und virtuelle Klassen 270<br />
notifyObservers (EventType e) {<br />
int len = observers.length;<br />
for (int i=0; i
3.2 Parametrische Typsysteme und virtuelle Klassen 271<br />
b) Rekursives Vorkommen des deklarierten Typs:<br />
Der deklarierte Typ K kann im Rumpf seiner Deklaration mit<br />
,,This“ bezeichnet werden. Dann werden in einer Subklasse<br />
SUBK alle diese Vorkommen als Vorkommen von SUBK<br />
interpretiert und entsprechend in weiteren Subtypen:<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 272<br />
class SLinkedList {<br />
This tail;<br />
public This getTail() { return tail; }<br />
}<br />
class SLinkedListOfObject extends SLinkedList {<br />
typedef Elem as Object;<br />
Elem head;<br />
public Elem getHead() { return head; }<br />
}<br />
class SLinkedListOfString extends SLinkedListObject {<br />
typedef Elem as String;<br />
// SLinkedListOfString.getTail liefert SLinkedListOfString<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 273<br />
Diskussion virtueller Typen<br />
• Vorteile:<br />
◦ keine neue Beziehung zwischen Typen (nur ,,ist Subtyp von“, nicht<br />
,,ist Typinstanz von“)<br />
◦ Subtypbeziehung zwischen ,,parametrischem“ und ,,instanziertem“<br />
Typ möglich<br />
◦ Rekursive Abhängigkeiten lassen sich flexibler behandeln<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 274<br />
• Nachteile:<br />
◦ Zusätzliche dynamische Typprüfung sind nötig (vor allem wegen<br />
kovarianten Methodenparametern):<br />
⊲ Verlust an statischer Typprüfbarkeit<br />
⊲ Verlust an Effizienz<br />
◦ rekursive Instanzierung (Beispiel Byte, Folie 245 ) nicht unterstützt.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 275<br />
• Anmerkungen:<br />
◦ Der Vorschlag von Thorup erlaubt es, virtuelle Typen als Subtypen<br />
mehrerer Typen zu deklarieren und dabei einen Klassentypen für die<br />
Erzeugung von Objekten auszuzeichnen.<br />
◦ Es gibt mittlerweile mehrere Arbeiten, die eine Integration von<br />
parametrischen und virtuellen Typen vorschlagen, z.B.:<br />
K. Bruce, M. Odersky, P. Wadler:<br />
A statically safe alternative to virtual types.<br />
European Conference on Object-Oriented Programming, 1998.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 276<br />
Realisierung virtueller Typen<br />
Typsicherheit wird in der Realisierung der vorgestellten<br />
Variante durch Einführen dynamischer Prüfungen erzielt.<br />
Wir unterscheiden primäre und überschreibende<br />
Deklarationen virtueller Typen.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 277<br />
Wesentliche Ideen:<br />
• Benutze für die Umsetzung eines virtuellen Typs T den<br />
Typ aus der primären Deklaration von T.<br />
• Definiere für jede primäre Deklaration eines virtuellen<br />
Typen T eine Cast-Methode. Diese Cast-Methode wird in<br />
Subtypen mit überschreibenden Deklarationen für T<br />
überschrieben.<br />
• Benutze die Cast-Methode zur Prüfung aktueller Parameter.<br />
• Um Typkorrektheit in den resultierenden Java-Programmen<br />
zu erreichen, füge weitere Typkonvertierungen ein (Casts).<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 278<br />
Beispiel(Realisierung virtueller Typen):<br />
class Vector {<br />
typedef ElemType as Object;<br />
void addElement( ElemType e ) { ... }<br />
...<br />
}<br />
class PointVector extends Vector {<br />
typedef ElemType as Point;<br />
void addElement( ElemType e ) {<br />
...<br />
e.getX()<br />
...<br />
}<br />
}<br />
PointVector pv;<br />
Point pnt;<br />
...<br />
pv.addElement(pnt);<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 279<br />
wird umgesetzt in<br />
class Vector {<br />
Object cast$T(Object o) { return o; }<br />
void check$addElement( Object o ) {<br />
this.addElement( this.cast$T(o) );<br />
}<br />
void addElement( Object e ) { ... }<br />
...<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.2 Parametrische Typsysteme und virtuelle Klassen 280<br />
class PointVector extends Vector {<br />
Object cast$T(Object o) {<br />
try {<br />
return (Point)o;<br />
} catch( ClassCastException c ) {<br />
throw new VirtualTypeCastException (...);<br />
}<br />
}<br />
void addElement( Object e$0 ) {<br />
Point e = (Point)e$0;<br />
...<br />
e.getX()<br />
...<br />
}<br />
}<br />
PointVector pv;<br />
Point pnt;<br />
...<br />
pv.check$addElement(pnt);<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 281<br />
3.3 Typsysteme zur Strukturierung von<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
Objektgeflechten
3.3 Typsysteme zur Strukturierung von Objektgeflechten 282<br />
Typisierungstechniken kann man nicht nur zur Vermeidung<br />
(klassischer) Typfehlern nutzen, sondern auch zur<br />
Sicherstellung anderer Invarianten.<br />
Wir betrachten hier die Sicherstellung von Kapselungseigenschaften<br />
(vgl. 2.4.2 ):<br />
3.3.1 Kapselung auf Paketebene: Confined Types<br />
3.3.2 Andere Strukturierungsanätze<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 283<br />
3.3.1 Kapselung auf Paketebene: Confined Types<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 284<br />
Ziel:<br />
Garantiere, dass Objekte bestimmter Typen nur vom<br />
Programmcode eines Packages manipuliert werden.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 285<br />
Grundideen:<br />
1. Betrachte jedes Paket P als Kapsel; d.h. alle Objekte (der<br />
Klassen) von P liegen in der gleichen Kapsel. Kapseln sind<br />
also disjunkt.<br />
2. Markiere Typen, deren Objekte gekapselt werden sollen,<br />
als ,,confined“. Die Objekte dieser Typen nennen wir<br />
gekapselt.<br />
3. Lege Regeln fest, die garantieren, dass Referenzen auf<br />
gekapselte Objekte eines Pakets P nur in Instanzvariablen,<br />
Parametern und lokalen Variablen von Objekten von P<br />
gehalten werden können.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 286<br />
outside<br />
ungekapselt<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
ungekapselt<br />
inside<br />
gekapselt
3.3 Typsysteme zur Strukturierung von Objektgeflechten 287<br />
Zusammenhang zu Typsystemen<br />
• Jede Variable bekommt als erweiterte Typinformation:<br />
◦ das Paket, zu dem sie gehört (implizit)<br />
• Jedes Objekt bekommt als erweiterte Typinformation:<br />
◦ das Paket, zu dem es gehört (implizit)<br />
◦ die Information, ob gekapselt oder nicht<br />
• Kapselungsverletzung (Typfehler) passiert, wenn eine<br />
Variable von Paket P ein gekapseltes Objekt eines anderen<br />
Pakets Q referenziert.<br />
• Es gibt statisch prüfbare Regeln, die Kapselungsverletzungen<br />
zur Laufzeit ausschließen.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 288<br />
Im Folgenden betrachten wir eine Erweiterung von Java um<br />
gekapselte Typen im obigen Sinne.<br />
Literatur:<br />
B. Bokowski, J. Vitek:<br />
Confined Types.<br />
OOPSLA, 1999.<br />
Bemerkung:<br />
Das Studium der Kapselungsregelungen ist auch für die<br />
Entwicklung von OO-Programmen im Allg. hilfreich.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 289<br />
Szenarien für Export von Referenzen<br />
package inside;<br />
public class C extends outside.B {<br />
void putReferences() {<br />
C c = new C();<br />
/*r1*/ outside.B.c1 = c;<br />
/*r2*/ outside.B.storeReference(c);<br />
/*r3*/ outside.B.c3s = new C[] {c};<br />
/*r4*/ calledByConfined();<br />
/*r5*/ implementedInSubclass();<br />
/*r6*/ throw new E();<br />
}<br />
void implementedInSubclass() { }<br />
/*r7*/ static C f = new C();<br />
/*r8*/ static C m() {<br />
return new C();<br />
}<br />
/*r9*/ static C[] fs = new C[]{new C()};<br />
/*r10*/ public C() { } }<br />
public class E extends RuntimeException { }<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 290<br />
Szenarien für Import von Referenzen<br />
package outside;<br />
public class B {<br />
/*r1*/ static inside.C c1;<br />
/*r2*/ static void storeReference(inside.C c2) { // store c2 }<br />
/*r3*/ static inside.C[] c3s;<br />
/*r4*/ void calledByConfined() { // store this }<br />
static void getReferences() {<br />
/*r7*/ inside.C c7 = inside.C.;<br />
/*r8*/ inside.C c8 = inside.C.m();<br />
/*r9*/ inside.C[] c9s = inside.C.fs;<br />
/*r10*/ inside.C c10 = new inside.C();<br />
D d = new D();<br />
try { d.putReferences();<br />
/*r6*/ } catch (inside.E ex) { // store ex }<br />
}<br />
}<br />
class D extends inside.C {<br />
/*r5*/ void implementedInSubclass() { // store this }<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 291<br />
Statische Kapselungsregeln<br />
Folgende Regeln garantieren die Kapselungsinvariante (dabei<br />
müssen Felder mit gekapseltem Elementtyp wie gekapselte<br />
Typen behandelt werden):<br />
C1: Gekapselte Typen dürfen weder public noch protected<br />
sein und nicht zum unbenannten globalen Paket gehören.<br />
C2: Subtypen von gekapselten Typen müssen auch gekapselt<br />
sein und zum gleichen Paket wie ihr Supertyp gehören.<br />
C3: Typerweiterung von gekapselten zu ungekapselten Typen<br />
ist unzulässig in Zuweisungen, Methodenaufrufen,<br />
Rückgabeanweisungen und Casts.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 292<br />
Die folgenden beiden Regeln benutzen den Begriff ,,anonyme<br />
Methode“ bzw. ,,anonyme Konstruktoren“, den wir weiter<br />
unten erläutern:<br />
C4: Methoden, die auf gekapselten Objekten aufgerufen<br />
werden, müssen entweder in gekapselten Klassen deklariert<br />
oder anonyme Methoden sein.<br />
C5: Konstruktoren, die von Konstruktoren gekapselten<br />
Klassen aufgerufen werden, müssen entweder in gekapselten<br />
Klassen deklariert oder anonyme Methoden sein.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 293<br />
C6: Subtypen von java.lang.Throwable und java.lang.Thread<br />
dürfen nicht als gekapselt deklariert werden.<br />
C7: Der Typ von öffentlichen und geschützten Attributen<br />
darf nicht gekapselt sein.<br />
C8: Der Ergebnistyp von öffentlichen und geschützten<br />
Methoden darf nicht gekapselt sein.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 294<br />
Definition(Anonyme Menge von Methoden):<br />
Eine Menge von Methoden kann als anonym deklariert<br />
werden, wenn sie die folgenden Bedingungen erfüllt:<br />
A1: Der implizite Parameter this wird nur benutzt, um auf<br />
Instanzvariablen zuzugreifen oder anonyme Methoden auf<br />
dem aktuellen Objekt aufzurufen.<br />
A2: Anonyme Methoden dürfen nur durch anonyme<br />
Methoden überschrieben werden.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 295<br />
A3: Native Methoden dürfen nicht anonym sein.<br />
Eine Menge von Konstruktoren kann als anonym deklariert<br />
werden, wenn jeder Konstruktor der Menge nur anonyme<br />
Konstruktoren aufruft.<br />
Bemerkung:<br />
• Das Verhalten anonymer Methoden wird nur von den<br />
aktuellen Parametern und den Werten der Instanzvariablen<br />
bestimmt.<br />
• Anonyme Methoden führen nicht zu neuen Aliasen für<br />
ihren impliziten Parameter.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 296<br />
3.3.2 Andere Strukturierungsansätze<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 297<br />
In der Literatur werden weitere Strukturierungsansätze<br />
diskutiert. Wir betrachten hier:<br />
• Ballontypen:<br />
◦ P. S. Almeida: Balloon Types: Controlling Sharing of State in Data<br />
Types. ECOOP ’97.<br />
• Besitzrelation:<br />
◦ D. G. Clarke, J. M. Potter, J. Noble: Ownership Types for Flexible<br />
Alias Protection. OOPSLA ’98.<br />
◦ Simple Ownership Types for Object Containment. ECOOP ’01.<br />
◦ P. Müller, A. Poetzsch-Heffter: A Type System for Controlling Representation<br />
Exposure in Java. Formal Techniques for Java Programs ’00.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 298<br />
Verwandte Themen sind:<br />
• Vermeidung von Aliasing<br />
• Realisierung von Schreibschutz<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 299<br />
Ballontypen<br />
Ein Typ kann als Ballontyp markiert werden.<br />
Objekte von Ballontypen heißen Ballonobjekte.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 300<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 301<br />
Definition(Cluster):<br />
Sei G der Graph mit Objekten als Knoten und mit den<br />
Referenzen zwischen Nicht-Ballonobjekten und von<br />
Ballonobjekten zu Nicht-Ballonobjekten als Kanten. Ein<br />
Cluster ist ein maximaler zusammenhängender Untergraph<br />
von G.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 302<br />
Definition(Interne Objekte):<br />
Ein Objekt O ist intern zu einem Ballonobjekt B genau<br />
dann, wenn gilt:<br />
• O ist ein Nicht-Ballonobjekt im gleichen Cluster wie B, oder<br />
• O ist ein Ballonobjekt, das von B oder einem Objekt im<br />
gleichen Cluster wie B referenziert wird, oder<br />
• es gibt ein zu B internes Ballonobjekt B’, zu dem O intern<br />
ist.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 303<br />
Definition(Externe Objekte):<br />
Ein Objekt O ist extern zu einem Ballonobjekt B genau<br />
dann, wenn es ungleich B ist und nicht intern zu B ist.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 304<br />
Balloninvariante:<br />
Für alle Ballonobjekte B gilt:<br />
• B wird von höchstens einer Instanzvariable referenziert.<br />
• Wenn es eine solche gespeicherte Referenz auf B gibt,<br />
kommt sie von einem zu B externen Objekt.<br />
• Kein internes Objekt zu B wird von einem Objekt<br />
referenziert, das extern zu B ist.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 305<br />
Bemerkung:<br />
• Die Invariante erlaubt es, dass lokale Variablen Objekte<br />
innerhalb eines Ballons referenzieren.<br />
Deshalb kann man einen Ballon auch nicht als die Menge<br />
der von einem Ballon erreichbaren Objekte definieren.<br />
• Um die Balloninvariante zu garantieren, benutzt Almeida<br />
folgende Techniken:<br />
◦ Zuweisung von Referenzen auf Ballonobjekte an Instanzvariablen ist<br />
im Allg. nicht erlaubt.<br />
◦ Datenflussanalyse<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 306<br />
Idee:<br />
Besitzrelation<br />
• Führe eine Besitzrelation zwischen Objekten ein:<br />
Objekt X gehört Objekt Y.<br />
• Benutze die Besitzrelation, um Kapselung zu realisieren:<br />
Nur der Besitzer darf auf die Objekte zugreifen, die ihm<br />
gehören.<br />
• Deklariere die Besitzrelation mittels erweiterter<br />
Typinformation.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 307<br />
Beispiel(Besitzrelation):<br />
class Engine {<br />
void start() { ... }<br />
void stop() { ... }<br />
}<br />
class Driver { ... }<br />
class Car {<br />
rep Engine engine; //Teil der Representation<br />
Driver driver; // kein Teil d.Representation<br />
Car() {<br />
engine = new rep Engine();<br />
driver = null;<br />
}<br />
rep Engine getEngine() { return engine; }<br />
void setEngine( rep Engine e){ engine=e; }<br />
void go () {<br />
if(driver!=null) engine.start();<br />
}<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 308<br />
class Main {<br />
void main() {<br />
Driver bob = new Driver();<br />
// kein Besitzer<br />
Car car = new Car(); // kein Besitzer<br />
car.driver = bob;<br />
car.go();<br />
car.engine.stop(); // unzulaessig<br />
car.getEngine().stop(); // unzulaessig<br />
rep Engine e = new rep Engine();<br />
car.setEngine(e); // unzulaessig<br />
}<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 309<br />
Die Besitzrelation ist eine binäre Relation zwischen<br />
Objekten. Bei der Erzeugung eines Objektes X wird<br />
festgelegt, wer Besitzer von X ist.<br />
Bei der einfachsten Variante gilt: Ein Objekt X ist<br />
• entweder global (hat also keinen Besitzer) oder<br />
• hat genau einen Besitzer.<br />
Besitzerinvariante:<br />
Alle Referenzpfade von einem globalen Objekt zu einem<br />
Objekt mit Besitzer B führen durch B.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.3 Typsysteme zur Strukturierung von Objektgeflechten 310<br />
Bemerkung:<br />
• Die Besitzerinvariante ist tendenziell allgemeiner als die<br />
Balloninvariante. Sie erlaubt Referenzen, die den Besitzbereich<br />
verlassen. Andererseits sind bei ihr temporäre<br />
Referenzen von außen in den Besitzbereich unzulässig.<br />
• In der beschriebenen Form bringt die Besitzrelation<br />
deutliche Restriktionen mit sich.<br />
• Es gibt unterschiedliche Umsetzungen und Verfeinerungen<br />
der Besitzrelation.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.4 Erweiterte statische Prüfung 311<br />
3.4 Erweiterte statische Prüfung<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.4 Erweiterte statische Prüfung 312<br />
Abschnitte 3.2 und 3.3 haben Erweiterungen von<br />
Typsystemen untersucht, die die Spezifikation und Prüfung<br />
von Eigenschaften erlauben, die sich mit klassischen<br />
Typsystem nicht ausdrücken lassen.<br />
Hier betrachten wir die Prüfung von Eigenschaften, die<br />
keiner gesonderten Spezifikation bedürfen, aber von der<br />
klassischen Typprüfung nicht erfasst werden.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.4 Erweiterte statische Prüfung 313<br />
Beispiel(Eigenschaften für ESP):<br />
Prüfe zur Übersetzungszeit, dass folgende Fehler nicht<br />
auftreten:<br />
• Dereferenzierung der Null-Referenz.<br />
• Feldzugriff mit unzulässigem Index.<br />
Während klassische und erweiterte Typsysteme meistens<br />
entscheidbar sind, zielt die erweiterte statische Prüfung auf<br />
Eigenschaften, die<br />
• in vielen Fällen entscheidbar,<br />
• aber im Allg. unentscheidbar sind.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.4 Erweiterte statische Prüfung 314<br />
3.4.1 Allgemeine Aspekte der ESP<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.4 Erweiterte statische Prüfung 315<br />
ESP ist eine junge Technik. Grundansatz:<br />
1. Bestimme die Eigenschaften, die analysiert werden sollen.<br />
2. Annotiere Programme soweit, dass die Prüfung<br />
automatisch durchgeführt werden kann:<br />
◦ Schnittstelleninformation<br />
◦ Beweisunterstützung<br />
3. Falls die Prüfung nicht gelingt, erweitere bzw. korrigiere<br />
die Annotationen oder korrigiere das Programm und setze<br />
mit 2. fort.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.4 Erweiterte statische Prüfung 316<br />
Beispiel(Programm mit Annotationen):<br />
1. In folgendem Programm kann es zu<br />
NullPointer-Ausnahmen kommen:<br />
class Scumble {<br />
int a;<br />
int m( Scumble s ){<br />
return s.a;<br />
}<br />
}<br />
Die Methode m braucht s!= null als Vorbedingung.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.4 Erweiterte statische Prüfung 317<br />
2. In folgendem Programm kann das Prüfwerkzeug<br />
möglicherweise nicht ableiten, dass i nach der Schleife<br />
gleich 8 ist:<br />
class MyClass {<br />
int[] a;<br />
MyClass() {<br />
int i = 1;<br />
while( i
3.4 Erweiterte statische Prüfung 318<br />
3.4.2 Das Werkzeug ESC/Java<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.4 Erweiterte statische Prüfung 319<br />
In den letzten Jahren sind mehrere Werkzeuge für das<br />
erweiterte statische Prüfen entwickelt worden. Wir<br />
betrachten hier den Extended Static Checker for Java<br />
(ESC/Java).<br />
ESC/Java prüft (annotierte) Java-Programme auf<br />
• Abwesenheit von Laufzeitfehlern/Ausnahmen,<br />
• Konsistenz von Annotationen und Programm.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.4 Erweiterte statische Prüfung 320<br />
Beispiel(Konsistenz):<br />
class Consistency {<br />
static int x;<br />
//@ ensures x == 7 ;<br />
static void initX() { x = 10; }<br />
}<br />
Prüfung liefert folgendes Ergebnis:<br />
Consistency: initX() ...<br />
-------------------------------------------<br />
Consistency.java:5: Warning: Postcondition<br />
possibly not established (Post)<br />
static void initX() { x = 10; }<br />
Associated declaration is "Consistency.java",<br />
line 4, col 6:<br />
//@ ensures x == 7 ;<br />
^<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.4 Erweiterte statische Prüfung 321<br />
Technische Aspekte von ESC/Java<br />
ESC/Java basiert auf:<br />
• Spezifikationssprache JML<br />
• precondition transformation<br />
• automatischen Theorembeweisen<br />
ESC/Java ist<br />
• logisch nicht korrekt, d.h. es liefert möglicherweise<br />
unberechtigte Warnungen;<br />
• logisch nicht vollständig, d.h. es gibt Eigenschaften, die<br />
gelten, aber nicht gezeigt werden können.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
3.4 Erweiterte statische Prüfung 322<br />
Die Inkorrektheit vereinfacht das Schließen, in dem nicht alle<br />
Möglichkeiten in Betracht gezogen werden.<br />
Der verwendete automatische Theorembeweiser unterstützt<br />
die Konstruktion von Gegenbeispielen.<br />
Vorführung: (ESC/Java)<br />
Siehe Vorlesung.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4. Spezifikation<br />
objektorientierter Programme
4. Spezifikation objektorientierter Programme<br />
4.1 Spezifikation von Typen<br />
4.2 Konformität von Subtypen<br />
4.3 Module und Modularität<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
324
Zentrale Aspekte der Objektorientierung:<br />
• Information Hiding & Kapselung:<br />
◦ Wie verhält sich ein Objekt intern?<br />
◦ Wie wirkt ein Objekt auf die Umgebung?<br />
• Subtypbeziehung:<br />
◦ Wann kann ich ein Objekt anstelle eines anderen verwenden?<br />
• Zusammenfassend:<br />
◦ Was ist die Bedeutung/Semantik eines Objekts?<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
325
Beispiele:<br />
1. Beschreibung von Verhalten bei privaten Attributen:<br />
public class WieWerdeIchBeschrieben {<br />
private int a = 0;<br />
public void set( int p ) { a = p; }<br />
public int get() { return a; }<br />
}<br />
Private Klassenkomponenten sollten nicht in einer<br />
öffentlichen Schnittstelle erscheinen.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
326
2. Nachrichten nach außen können die Umgebung ändern:<br />
public class Umweltverschmutzung {<br />
public void nurlokal( Object mo ) {<br />
do_something_good();<br />
if( mo instanceof Atmosphere )<br />
((Atmosphere) mo).pollute();<br />
}<br />
}<br />
Wie beschreibt man die Auswirkungen auf die Umgebung?<br />
Insbesondere auch die Invarianten der Umgebung.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
327
3. Für konformes Verhalten reicht Typkorrektheit nicht aus:<br />
public class Superklasse<br />
{ public int a = 0;<br />
public void dincrA() { a++; }<br />
}<br />
public class Subklasse extends Superklasse<br />
{ public void dincrA() { a--; }<br />
}<br />
Macht es Sinn, ein Subklasse-Objekt anstelle eines<br />
Superklasse-Objekts zu verwenden?<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
328
Lernziele:<br />
• Spezifikationstechniken<br />
• Beschreibung von Programmbausteinen<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
329
4.1 Spezifikation von Typen 330<br />
4.1 Spezifikation von Typen<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 331<br />
Ziel:<br />
Spezifikation der Eigenschaften eines Typs unabhängig von<br />
seiner/seinen Implementierungen.<br />
Problematik:<br />
• Vokabular/Framework zur Formulierung der Eigenschaften<br />
• Information Hiding: private und geschützte<br />
Implementierungsteile können nicht in öffentlicher<br />
Spezifikation benutzt werden.<br />
• Zusammenspiel zwischen deklarativer Spezifikation und<br />
objektorientierter Implementierung<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 332<br />
Ansätze:<br />
• Spezifikation mit programmiersprachlichen Mitteln<br />
• Spezifikation mit erweiterten programmiersprachlichen<br />
Mitteln unter Einhaltung der Ausführbarkeit<br />
• Spezifikation mit abstrakteren Sprachmitteln<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 333<br />
Vorgehen:<br />
• Leichte Spezifikationen<br />
• Spezifikation einzelner Objekte<br />
◦ Invarianten<br />
◦ Verhalten von Methoden<br />
◦ Umgebungseigenschaften<br />
• Spezifikation mit abstrakten Variablen<br />
◦ abstrakte Variablen<br />
◦ Abstraktionsfunktionen<br />
◦ abstrakte Spezifikation von Umgebungseigenschaften<br />
• Spezifikation zusammenhängender Objekte<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 334<br />
Dabei betrachten wir als Sprachmittel ausführbare<br />
Spezifikationen in JML , der Java Modelling Language.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 335<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
4.1.1 Leichte Spezifikationen
4.1 Spezifikation von Typen 336<br />
Definition(leichte Spezifikation):<br />
Eine leichte Spezifikation beschreibt wichtige Eigenschaften<br />
von Objekten und Methoden, die ohne großen Aufwand<br />
beschrieben werden können.<br />
Leichte Spezifikationen streben nicht die vollständige<br />
Beschreibung relevanten Verhaltens an.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 337<br />
Beispiel(leichte Spezifikation):<br />
public class Bag {<br />
//@ requires input != null;<br />
public Bag(int[] input) {<br />
n = input.length;<br />
a = new int[n];<br />
System.arraycopy(input, 0, a, 0, n);<br />
} ...<br />
}<br />
Leichte Spezifikationen sind insbesondere ein präzises<br />
Dokumentationsmittel.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 338<br />
Bemerkung:<br />
Leichte Spezifikationen können auch zur Annotation privater<br />
Programmelemente verwendet werden, um die Lesbarkeit<br />
oder Prüfbarkeit von Programmen zu verbessern.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 339<br />
Beispiel(leichte Spezifikation):<br />
public final<br />
class String implements ... {<br />
/** Used for character storage. */<br />
//@ private invariant value != null ;<br />
private char value[];<br />
/** First index of the storage used. */<br />
//@ private invariant offset >= 0<br />
private int offset;<br />
/** Number of characters in the String */<br />
//@ private invariant count >= 0 ;<br />
private int count;<br />
/*@ private invariant<br />
@ offset + count
4.1 Spezifikation von Typen 340<br />
4.1.2 Spezifikation einzelner Objekte<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 341<br />
Vereinfachende Annahmen:<br />
• Spezifikationen hängen nur von dem Zustand jeweils eines<br />
Objekts ab.<br />
• Relevante Attribute sind dem Anwender bekannt.<br />
• Methoden ändern nur das Objekt, auf dem sie aufgerufen<br />
wurden.<br />
• Kein Subtyping, keine Vererbung.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 342<br />
Spezifiziere:<br />
• die möglichen Zustände der Objekte durch Invarianten<br />
über den Attributwerten;<br />
• das Verhalten von Methoden durch die von ihnen<br />
vorgenommenen Änderungen der Attributwerte;<br />
• Umgebungseigenschaften durch Angabe, welche<br />
Attributwerte von Methoden nicht verändert werden.<br />
Beispiel:<br />
public class Point {<br />
/** Koordinaten */<br />
/*@ spec_public @*/ private float x, y;<br />
private float dist;<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 343<br />
Invarianten<br />
Invarianten spezifizieren die Bereichseinschränkungen für die<br />
Attributwerte und die Beziehungen zwischen Attributwerten.<br />
Beispiel(Invarianten):<br />
public class Point {<br />
...<br />
//@ public invariant x >= 0.0 && y >= 0.0 ;<br />
}<br />
/*@ private invariant<br />
@ dist == Math.sqrt(x*x+y*y) ;<br />
@*/<br />
...<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 344<br />
Verhalten von Konstruktoren und Methoden<br />
Konstruktoren müssen die Invarianten etablieren.<br />
Methoden müssen die Invarianten erhalten.<br />
Die Vorbedingung für ihre Anwendung und ihr Einfluss auf<br />
die Attributwerte ihres Zielobjektes und ihr Ergebnis werden<br />
mit Vor- und Nachbedingungen spezifiziert.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 345<br />
Beispiel(Verhalten von Konstruktoren und Methoden):<br />
public class Point {<br />
...<br />
/** Erzeugen eines Punktes */<br />
/*@ public normal_behavior<br />
@ requires x >= 0.0 && y >= 0.0 ;<br />
@ ensures this.x == x && this.y == y;<br />
@ also<br />
@ public exceptional_behavior<br />
@ requires x < 0.0 || y < 0.0 ;<br />
@ signals (IllegalArgumentException)<br />
@*/<br />
public Point ( float x, float y ) { ... }<br />
/*@ public normal_behavior<br />
@ ensures \result == this.x ;<br />
@*/<br />
public float getX() { ... }<br />
...<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
}<br />
4.1 Spezifikation von Typen 346<br />
/** Entfernung vom Ursprung */<br />
/*@ public normal_behavior<br />
@ ensures \result == Math.sqrt(x*x+y*y);<br />
@*/<br />
public float distance() { ... }<br />
/** Verschieben dieses Punktes */<br />
/*@ public normal_behavior<br />
@ requires x+dx >= 0.0 && y+dy >= 0.0 ;<br />
@ ensures x == \old(x)+dx && y == \old(y)+dy ;<br />
@ also<br />
@ public exceptional_behavior<br />
@ requires x+dx < 0.0 || y+dy < 0.0 ;<br />
@ signals (IllegalArgumentException)<br />
@*/<br />
public void move( float dx, float dy ){ ...}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 347<br />
Bemerkung:<br />
• Vor- und Nachbedingungsspezifikationen liefern keine<br />
vollständige Aussage darüber, was sich verändert (z.B.<br />
bzgl. Attribut dist bei Ausführung von move).<br />
• Sie liefern keine Aussage darüber, was sich nicht verändert.<br />
• Obiges Beispiel ist keine zulässige JML-Spezifikation (s.u.).<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 348<br />
Spezifikation von Umgebungseigenschaften<br />
Veränderungsspezifikationen beschreiben, welche Variablen<br />
ihren Wert bei Ausführung einer Methode nicht verändern,<br />
indem sie die Variablen spezifizieren, die sich ändern dürfen.<br />
Grund für indirektes Vorgehen:<br />
• Es gibt weniger Variablen, die sich ändern.<br />
• Im Allg. sind nicht alle Variablen des Programms bekannt.<br />
Damit ist insbesondere spezifiziert, welche Eigenschaften der<br />
Umgebung (engl. frame properties) erhalten bleiben.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 349<br />
Spezifikationsmittel:<br />
Veränderungsklausel (modifies, assignable clause):<br />
assignable 〈Liste bedingter Variablenausdrücke〉<br />
Bespiele:<br />
assignable x, this.a, p.a.b<br />
assignable x, this.a if(this==p)<br />
Bemerkung:<br />
Schlüsselwort modifies ist gleichbedeutend mit<br />
assignable.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 350<br />
Bedeutung:<br />
Eine Methode bzw. ein Konstruktor darf nur an Instanzoder<br />
Klassenvariable zuweisen, die<br />
• in der Veränderungsklausel genannt ist und deren<br />
zugehörige Bedingung im Vorzustand erfüllt ist oder<br />
• die erst während der Methodenausführung allokiert werden.<br />
Fehlt eine Veränderungsklausel, hat es die gleiche Bedeutung<br />
wie eine Veränderungsklausel mit leerer Liste.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 351<br />
Beispiel(Spezifikationsmittel):<br />
public class Point {<br />
...<br />
/*@ public normal_behavior<br />
@ requires x >= 0.0 && y >= 0.0 ;<br />
@ assignable this.x, this.y ;<br />
@ ensures this.x == x && this.y == y;<br />
@ also<br />
@ private normal_behavior<br />
@ requires x >= 0.0 && y >= 0.0 ;<br />
@ assignable dist ;<br />
@ also<br />
@ public exceptional_behavior<br />
@ requires x < 0.0 || y < 0.0 ;<br />
@ signals (IllegalArgumentException)<br />
@*/<br />
public Point ( float x, float y ) { ...}<br />
...<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
}<br />
4.1 Spezifikation von Typen 352<br />
/*@ public normal_behavior<br />
@ ensures \result == this.x ;<br />
@*/<br />
public float getX() { ... }<br />
...<br />
/*@ public normal_behavior<br />
@ requires x+dx >= 0.0 && y+dy >= 0.0;<br />
@ assignable x, y ;<br />
@ ensures x == \old(x)+dx && y == \old(y)+dy ;<br />
@ private normal_behavior<br />
@ requires x+dx >= 0.0 && y+dy >= 0.0;<br />
@ assignable dist ;<br />
@ also<br />
@ public exceptional_behavior<br />
@ requires x+dx < 0.0 || y+dy < 0.0 ;<br />
@ signals (IllegalArgumentException)<br />
@*/<br />
public void move( float dx, float dy ){ ...}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 353<br />
Bemerkung:<br />
Private Veränderungsklauseln sind unwichtig für die<br />
Dokumentation der öffentlichen Schnittstelle, aber nötig für<br />
das Prüfwerkzeug.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 354<br />
4.1.3 Spezifikation mit abstrakten Variablen<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 355<br />
Abstrakte Variablen/Attribute werden zur Spezifikation<br />
benötigt, wenn<br />
• konkrete Attribute nicht deklariert sind oder<br />
• die Zugreifbarkeitsregeln die Verwendung konkreter<br />
Attribute in Spezifikationen nicht gestatten oder<br />
• Austauschbarkeit der Implementierung erreicht werden soll.<br />
Syntax: Abstrakte Variablen/Attribute werden in JML wie<br />
Attribute, allerdings mit dem zusätzlichen Schlüsselwort<br />
model als Modifikator vereinbart. In JML haben abstrakte<br />
Attribute einen Java-Typ.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 356<br />
Bedeutung:<br />
Abstrakte Attribute hängen von konkreten Attributen oder<br />
anderen abstrakten Attributen ab.<br />
Die Abhängigkeit muss in einer Abhängigkeitsklausel<br />
spezifiziert werden.<br />
Der Wert von einem abstrakten Attribut a eines Objekts<br />
ergibt sich aus den Werten der Attribute, von denen a<br />
abhängt. Wie er sich berechnet, wird in einer Repräsentationsklausel<br />
festgelegt.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 357<br />
Beispiel(Abstrakte Attribute):<br />
public class Point {<br />
/** Koordinaten */<br />
//@ public model float x, y;<br />
//@ public invariant x >= 0.0 && y >= 0.0;<br />
private double dist, angle ;<br />
/*@ private invariant dist >= 0.0<br />
@ && 0.0
4.1 Spezifikation von Typen 358<br />
Abstrakte Variablen und<br />
Umgebungseigenschaften<br />
Das Recht, eine abstrakte Variable a verändern zu dürfen,<br />
impliziert das Recht, alle konkreten Variablen zu ändern, von<br />
denen a abhängt.<br />
Beispiel(Abstrakte Variablen und Umgebungseigenschaften<br />
Der Konstruktor Point darf dist und angle verändern:<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 359<br />
public class Point {<br />
/*@ public normal_behavior<br />
@ requires x >= 0.0 && y >= 0.0 ;<br />
@ assignable this.x, this.y ;<br />
@ ensures this.x == x && this.y == y;<br />
@ also<br />
@ public exceptional_behavior<br />
@ requires x < 0.0 || y < 0.0 ;<br />
@ signals (IllegalArgumentException)<br />
@*/<br />
public Point ( float x, float y ) { ...}<br />
/*@ public normal_behavior<br />
@ ensures \result == this.x ;<br />
@*/<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
}<br />
4.1 Spezifikation von Typen 360<br />
public float getX() { ... }<br />
/*@ public normal_behavior<br />
@ requires x+dx >= 0.0 && y+dy >= 0.0;<br />
@ assignable x, y ;<br />
@ ensures x == \old(x)+dx && y == \old(y)+dy ;<br />
@ also<br />
@ public exceptional_behavior<br />
@ requires x+dx < 0.0 || y+dy < 0.0 ;<br />
@ signals (IllegalArgumentException)<br />
@*/<br />
public void move( float dx, float dy ){ ...}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 361<br />
Bemerkung:<br />
• Die Spezifikation der Veränderung von dist ist nicht mehr<br />
nötig, da x und y von dist abhängen.<br />
• Die Gleichheit in den Zusicherungsklauseln ist<br />
problematisch.<br />
Mit dem folgendem Beispiel demonstrieren wir die Spezifikation<br />
eines Typs, für den keine Attribute deklariert sind.<br />
Die Spezifikation benutzt einen komplexeren, in JML<br />
vordefinierten seiteneffektfreien Typ JMLObjectSequence:<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 362<br />
Beispiel(abstrakte Variablen):<br />
//@ model import org.jmlspecs.models.*;<br />
public abstract class UnboundedStack {<br />
/*@ public model JMLObjectSequence theStack<br />
@ initially theStack != null && theStack.isEmpty();<br />
@*/<br />
//@ public invariant theStack != null;<br />
/*@ public normal_behavior<br />
@ requires !theStack.isEmpty();<br />
@ assignable theStack;<br />
@ ensures theStack.equals( \old(theStack.trailer()));<br />
@*/<br />
public abstract void pop( );<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
}<br />
4.1 Spezifikation von Typen 363<br />
/*@ public normal_behavior<br />
@ assignable theStack;<br />
@ ensures theStack.equals( \old(theStack.insertFront(x)));<br />
@*/<br />
public abstract void push(Object x);<br />
/*@ public normal_behavior<br />
@ requires !theStack.isEmpty();<br />
@ ensures \result == theStack.first();<br />
@*/<br />
public abstract Object top( );<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 364<br />
package org.jmlspecs.models;<br />
public /*@ pure @*/ class JMLObjectSequence<br />
implements JMLCollection<br />
{<br />
public /*@ pure @*/<br />
boolean equals(Object obj) { ... }<br />
public /*@ pure @*/<br />
boolean isEmpty() { ... }<br />
public /*@ pure @*/<br />
Object first()<br />
throws JMLSequenceException { ... }<br />
public /*@ pure @*/<br />
/*@ non_null @*/ JMLObjectSequence<br />
insertFront(Object item)<br />
throws IllegalStateException { ... }<br />
...<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 365<br />
Methoden sind pure, wenn sie keine Seiteneffekte haben<br />
(assignable \nothing).<br />
Konstruktoren sind pure, wenn sie nur Objektattribute<br />
verändern und ansonsten keine Seiteneffekte haben.<br />
Klassen- und Schnittstellentypen, die als pure deklariert sind,<br />
dürfen nur pure Methoden und Konstruktoren haben.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 366<br />
4.1.4 Spezifikation zusammenhängender Objekte<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 367<br />
Objekte erbringen ihre Funktionalität meist im Zusammenwirken<br />
mit anderen Objekten. Wir betrachten hier die Fälle:<br />
• Aggregation<br />
• Komposition<br />
• Rekursive Objektbeziehungen<br />
Aggregation:<br />
Aggregation modelliert eine hat-ein-Beziehung zwischen<br />
einem Objekt X und Teilen von X. Teilobjekte sind<br />
üblicherweise außerhalb von X bekannt und zugreifbar;<br />
sie können auch Teil anderer Objekte sein.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 368<br />
Bemerkung:<br />
Die Zugreifbarkeit von außen ist problematisch, da<br />
Invarianten des aggregierenden Objekts verletzt werden<br />
können.<br />
Beispiel(Aggregation):<br />
public class Line {<br />
public /*@ non_null @*/ Point left,right;<br />
//@ public invariant left != right ;<br />
//@ public invariant left.x
}<br />
4.1 Spezifikation von Typen 369<br />
/*@ public normal_behavior<br />
@ requires p1 != null && p2 != null &&<br />
@ p1 != p2;<br />
@ assignable left, right;<br />
@ ensures ((left == p1 && right == p2)<br />
@ || (left == p2 && right == p1))<br />
@ && linebreadth == 1 && ... ;<br />
@*/<br />
public Line( Point p1, Point p2 ) { ...}<br />
...<br />
/*@ public normal_behavior<br />
@ ensures \result == left ;<br />
@*/<br />
public Point getLeft() { ... }<br />
/*@ public normal_behavior<br />
@ ensures \result == ... ;<br />
@*/<br />
public float length() { ... }<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 370<br />
Beachte:<br />
• Ein Punkt kann zu mehreren Linien gehören.<br />
• Die zweite Invariante kann durch Verschieben eines der<br />
Endpunkte verletzt werden. Deshalb besser:<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 371<br />
public class Line {<br />
public /*@ non_null @*/ Point from,to;<br />
//@ public invariant from != to ;<br />
public /*@ non_null @*/ Color linecolor;<br />
public int linebreadth ;<br />
/*@ public normal_behavior<br />
@ requires p1! = null && p2 != null &&<br />
@ p1 != p2<br />
@ assignable from, to;<br />
@ ensures form == p1 && to == p2<br />
@ && linebreadth == 1 && ...<br />
@ ...<br />
@*/<br />
public Line( Point p1, Point p2 ) { ...}<br />
...<br />
/*@ public normal_behavior<br />
@ ensures \result ==<br />
@ from.x
4.1 Spezifikation von Typen 372<br />
Komposition:<br />
Komposition modelliert eine exklusive Besitzerbeziehung<br />
zwischen einem Objekt X und seinen Teilen.<br />
Teilobjekte sind üblicherweise außerhalb von X bekannt und<br />
eingeschränkt zugreifbar; sie dürfen nicht direkter Teil<br />
mehrerer Objekte sein.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 373<br />
Beispiel(Komposition):<br />
Wir betrachten eine Klasse für Streckenzüge, die aus Linien<br />
zusammengesetzt sind.<br />
Die Streckenzüge lassen sich von außen durch Verschieben<br />
der Punkte verändern.<br />
Line<br />
from:<br />
to:<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
Polyline<br />
Line<br />
from:<br />
to:<br />
Point Point Point
4.1 Spezifikation von Typen 374<br />
Um zu verhindern, dass ein Line-Objekt Teil zweier<br />
Polylinien wird, kann man:<br />
• die Linien kapseln;<br />
• den Einbau von Linien kontrollieren.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 375<br />
Rekursive Objektbeziehungen:<br />
Die Eigenschaften und Invarianten rekursiver Klassen<br />
erstrecken sich oft über eine unbegrenzte Anzahl von<br />
Objekten.<br />
Für ihre Spezifikation benötigt man meist Hilfsfunktionen.<br />
Beispiel(rekursive Klasse):<br />
public class IntList {<br />
private int elem;<br />
private IntList next;<br />
//@ private invariant !this.reach(next) ;<br />
/*@ pure @*/ boolean reach( IntList il ){<br />
// aber wie beschreibe ich reach<br />
}<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.1 Spezifikation von Typen 376<br />
Bemerkung:<br />
Obiges Beispiel zeigt:<br />
• Schranken der Ausdruckskraft der demonstrierten<br />
Spezifikationstechnik;<br />
• Problematik der Verwendung partieller Prädikate.<br />
• Eine allgemeine Spezifikationsmethode für rekursive<br />
Klassen fehlt noch.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 377<br />
4.2 Konformität von Subtypen<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 378<br />
Die Subtypbeziehung wird in Programmiersprachen meist<br />
rein syntaktisch verstanden:<br />
Was muss ein Subtypobjekt für Eigenschaften haben, damit<br />
an Stellen, an denen Supertypobjekte erwartet werden,<br />
• keine Typfehlern auftreten und<br />
• zu Methodenaufrufen immer geeignete Methodenimplementierungen<br />
existieren.<br />
Was bedeutet es semantisch, ein Subtyp zu sein?<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 379<br />
Probleme:<br />
Der Subtyp soll eine Spezialisierung des Supertyps sein. Auf<br />
Basis der operationellen Semantik lässt sich Spezialisierung<br />
nur schwer definieren:<br />
• Spezialisierung von abstrakten Typen<br />
• Erweiterung des Zustandsraums<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 380<br />
Ansatz:<br />
Definiere die Subtypbeziehungen auf Basis der<br />
Spezifikationen:<br />
• Jedes Subtypobjekt muss die Spezifikationen der<br />
Supertypen erfüllen.<br />
• Für Vor- und Nachbedingungsspezifikationen:<br />
◦ pre[Supertyp] => pre[Subtyp]<br />
◦ post[Subtyp] => post[Supertyp]<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 381<br />
Vorgehen:<br />
• Vor- und Nachbedingungsspezifikation ohne abstrakte<br />
Variablen und Abstraktion<br />
• Vor- und Nachbedingungsspezifikation mit abstrakten<br />
Variablen und Abstraktion<br />
• Behandlung von Invarianten<br />
• Umgebungseigenschaften<br />
• Zusammenwirken der Techniken<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 382<br />
Konkrete Pre-Post-Spezifikationen<br />
Jede Vor- bzw. Nachbedingung einer Methode im Supertyp<br />
kann als Vor- bzw. Nachbedingung der entsprechenden<br />
Methode des Subtyps interpretiert werden:<br />
• Vererben der Spezifikation<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 383<br />
Subtypen ohne zusätzliche Attribute:<br />
• Ererbte Methode:<br />
◦ Spezifikation wird geerbt und nicht erweitert.<br />
•<br />
Überschreibende Methode:<br />
◦ Vorbedingung wird geerbt und nicht erweitert.<br />
◦ Nachbedingung wird geerbt und ggf. um Konjunkte erweitert, d.h.<br />
verstärkt.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 384<br />
Beispiel(Konkrete Pre-Post-Spezifikationen):<br />
class C {<br />
/*@ public normal_behavior<br />
@ requires P<br />
@ ensures Q ;<br />
@*/<br />
C m(){ ... }<br />
}<br />
class D extends C {<br />
/*@ also<br />
@ public normal_behavior<br />
@ requires P<br />
@ ensures \result instanceof D ;<br />
@*/<br />
C m(){ ... }<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 385<br />
Zusätzliche Methode:<br />
• keine Einschränkungen an Verhalten.<br />
Bemerkung:<br />
Entsprechende Spezifikationsverfeinerungen, wie hier fürs<br />
normale Verhalten gelten fürs Ausnahmeverhalten.<br />
Subtypen mit zusätzlichen Attributen:<br />
Ist der Zustandsraum im Subtyp erweitert, kann neben den<br />
oben erläuterten Spezifikationsverfeinerungen eine<br />
Ergänzung der Vorbedingung bei überschreibenden<br />
Methoden sinnvoll sein.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 386<br />
Es reicht zu verlangen, dass:<br />
• pre[Supertyp] && this instanceof Subtyp ⇒pre[Subtyp]<br />
• post[Subtyp] && this instanceof Subtyp ⇒ post[Supertyp]<br />
Bemerkung:<br />
• Diese Abschwächung setzt normalerweise voraus, dass ein<br />
Supertyp seine Subtypen kennt.<br />
• Die Problematik des erweiterten Zustandsraums ist ein<br />
wichtiges Argument für die Verwendung von Abstraktion.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 387<br />
Abstrakte Pre-Post-Spezifikationen<br />
Die Repräsentation der abstrakten Attribute durch die<br />
konkreten kann von Subtyp zu Subtyp verschieden sein.<br />
Die abstrakt formulierten Bedingungen werden dementsprechend<br />
unterschiedlich konkretisiert.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 388<br />
Beispiel(Abstrakte Pre-Post-Spezifikationen):<br />
class C {<br />
//@ public model boolean valid;<br />
//@ public model AS state;<br />
/*@ public normal_behavior<br />
@ requires valid && r(state)<br />
@ ensures q(state) ;<br />
@*/<br />
void m(){ ... }<br />
}<br />
class D extends C {<br />
private BD d;<br />
//@ private depends valid
4.2 Konformität von Subtypen 389<br />
class E extends C {<br />
private BE e;<br />
//@ private depends valid
4.2 Konformität von Subtypen 390<br />
Bemerkung:<br />
• Häufig geht man auch von einer expliziten<br />
Abstraktionsfunktion aus, die den Zustandsraum des<br />
Subtyps in den des Supertyps abstrahiert.<br />
• Die abstrakten Variablen ermöglichen zwei Arten der<br />
,,Zustandserweiterung“:<br />
◦ Überschreiben der Repräsentationsfunktion<br />
◦ zusätzliche abstrakte Variablen<br />
• Die Variationen in den Subtypen können von der<br />
Repräsentationsfunktion aufgefangen werden.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 391<br />
Behandlung von Invarianten<br />
Im Prinzip lassen sich Invarianten durch Vor- und<br />
Nachbedingungen ausdrücken.<br />
Spezifikationstechnisch sind sie aber wichtig, da sie es<br />
ermöglichen, in Supertypen das Verhalten zusätzlicher<br />
Subtypmethoden einzuschränken:<br />
• Invarianten von Supertypen müssen auch von zusätzlichen<br />
Subtypmethoden erfüllt werden.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 392<br />
Beispiel(Behandlung von Invarianten):<br />
class C {<br />
public int a = 0;<br />
//@ public invariant a >= 0;<br />
...<br />
// keine Deklaration von m<br />
}<br />
class D extends C {<br />
...<br />
void m(){ a = -1; } // verletzt Invariante<br />
...<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 393<br />
Ansatz:<br />
• Invarianten des Supertyps müssen auch von den Subtypen<br />
erfüllt werden:<br />
inv[Subtyp]⇒ inv[Supertyp]<br />
• Vorgehen:<br />
Vererbe Invarianten an Subtypen und bilde die Konjunktion<br />
mit den in den Subtypen angegebenen Invarianten.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 394<br />
Problematik:<br />
Die Invarianten gelten normalerweise nicht in jedem<br />
Zustand. Was ist ihre präzise Bedeutung? Was muss im<br />
Vorzustand eines Methodenaufrufs gelten?<br />
Für die Bedeutung von Invarianten in Spezifikationssprachen<br />
gibt es bisher keine einheitliche Lösung.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 395<br />
Semantische Varianten:<br />
1. Invariante über eingeschränkte Zustandsmenge:<br />
JML: ,,Invariants have to hold in each state outside of a<br />
public method’s execution and at the beginning and end of<br />
such execution.“<br />
2. Transformation in Vor- und Nachbedingungen:<br />
Verifikationsansätze: Invarianten müssen im Nachzustand<br />
von Konstruktoraufrufen gelten. Wenn sie im Vorzustand<br />
von Methoden gelten, müssen sie auch im Nachzustand<br />
gelten.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 396<br />
Für die Verifikation bringen beide Varianten ein Problem mit<br />
sich:<br />
Sei S ein Subtyp von T, m eine Methode in T und x eine<br />
Variable vom Typ T:<br />
... x.m(...) ...<br />
In der Verifikation wird man inv[T] als Vorbedingung<br />
voraussetzen. Als Vorbedingung der Methoden von S<br />
benötigt man aber im Allg. inv[S].<br />
Ziel ist aber die Verifikation ohne Kenntnis aller Subtypen.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 397<br />
Beispiel(Behandlung von Invarianten):<br />
class C {<br />
public int a = 0;<br />
//@ public invariant a => 0;<br />
...<br />
void m(){<br />
... // erhaelt die Invariante<br />
}<br />
}<br />
class Foo {<br />
void mfoo() {<br />
... x.m() ...<br />
}<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 398<br />
class D extends C {<br />
public int b = 0;<br />
//@ public invariant a > 1;<br />
//@ public invariant b => 0;<br />
...<br />
void m(){<br />
b = 4 / a ;<br />
... // erhaelt beide Invarianten<br />
}<br />
}<br />
Problem:<br />
Lege die Vorbedingung für den Aufruf von x.m() fest.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 399<br />
Lösungsansatz:<br />
Betrachte als Invariante eines Typs T die folgende Formel<br />
INV[T]:<br />
∀ Typen S: S ≤ T ⇒ ( typ(this)=S ⇒ inv[S] )<br />
wobei inv[S] bei gegebenem S die Invariante der<br />
Implementierung von S bezeichnet. Dann gilt für einen<br />
Subtyp U von T:<br />
typ(this) = U ⇒ ( inv[U] ⇔ INV[T] )<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 400<br />
Bemerkung:<br />
Darüber hinaus muss man im Allg. auch zeigen, dass eine<br />
Methode von T die Invarianten aller anderen Typen<br />
unverändert lässt.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 401<br />
Umgebungseigenschaften<br />
Die Spezifikation von Umgebungseigenschaften ist mit zwei<br />
Problemen konfrontiert:<br />
• Information Hiding: nicht alle veränderbaren Variablen<br />
können in der Spezifikation genannt werden.<br />
• Zustandserweiterung: Die Supertypspezifikation sollte<br />
unabhängig von den Implementierungen der Subtypen sein.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 402<br />
Beispiel(Umgebungseigenschaften):<br />
class C {<br />
public int a = 0;<br />
private int b = 0;<br />
public static int c = 123;<br />
...<br />
/*@ public normal_behavior<br />
@ assignable a;<br />
@*/<br />
public void m(){ a++; b++; }<br />
}<br />
class Foo {<br />
void mfoo() {<br />
... x.m() ...<br />
}<br />
}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
class D extends C {<br />
public int d = 0;<br />
...<br />
public void m(){<br />
super.m();<br />
d = 87;<br />
C.c = 4 ;<br />
...<br />
}<br />
}
4.2 Konformität von Subtypen 403<br />
Ansatz:<br />
• Verwende abstrakte Attribute/Variablen, Abhängigkeitsund<br />
Repräsentationsklauseln.<br />
• Information Hiding: Abstrakte Attribute können von nicht<br />
zugreifbaren Attributen abhängen.<br />
• Zustandserweiterung: Die Abhängigkeiten abstrakter<br />
Attribute können in Subtypen erweitert werden.<br />
(Beispiel dazu im folgenden Unterabschnitt)<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 404<br />
Zusammenwirken der Techniken<br />
Spezifikationstechniken für objektorientierte Programme<br />
verfolgen zwei Ziele:<br />
• Spezifikation von Eigenschaften durch Annotation von<br />
Programmen.<br />
• Vollständige Spezifikation von Typen und damit auch<br />
Grundlage für das Verständnis der Verhaltenskonformität<br />
bei Subtypen.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 405<br />
Vorgehen:<br />
• Zusammenwirken der Techniken mit Schwerpunkt<br />
abstrakte Spezifikation an einem Beispiel<br />
• Verhaltenskonformität bei Subtypen<br />
Beispiel(Zusammenwirken der Techniken):<br />
Das behandelte Beispiel ist eine Java-Adaption des zentralen<br />
Beispiels aus:<br />
K. R. M. Leino, G. Nelson: Data abstraction and<br />
information hiding, Transactions on Programming Languages<br />
and Systems 24(5): 491-553 (2002).<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 406<br />
Reader<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
BuffReader BlankReader<br />
BlankReaderImpl
4.2 Konformität von Subtypen 407<br />
Das Beispiel demonstriert vor allem die Behandlung von<br />
Zustandserweiterungen in Subtypen.<br />
public interface Reader {<br />
//@ public model instance boolean valid;<br />
//@ public model instance Object state;<br />
/*@ public normal_behavior<br />
@ requires valid;<br />
@ assignable state;<br />
@ ensures -1
4.2 Konformität von Subtypen 408<br />
public abstract class BuffReader implements Reader {<br />
protected /*@ spec_public @*/ int lo, cur, hi;<br />
protected /*@ spec_public @*/ char[] buff;<br />
//@ public model boolean svalid;<br />
/*@ public represents valid
}<br />
4.2 Konformität von Subtypen 409<br />
/*@ public normal_behavior<br />
@ requires valid;<br />
@ assignable state;<br />
@ ensures cur == \old(cur) ;<br />
@*/<br />
public abstract void refill();<br />
//@ depends valid
4.2 Konformität von Subtypen 410<br />
Eine triviale Anwendung von BlankReader und<br />
BlankReaderImpl (s. nächste Seite):<br />
public class ReaderTest {<br />
public static void main( String[] args ) {<br />
BlankReader br = new BlankReaderImpl();<br />
br.init(1000000);<br />
}<br />
}<br />
int count = 0;<br />
int chr;<br />
do {<br />
chr = br.getChar();<br />
count++;<br />
} while( chr != -1 );<br />
br.close();<br />
System.out.println(count);<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 411<br />
public class BlankReaderImpl<br />
extends BuffReader<br />
implements BlankReader<br />
{<br />
private int num;<br />
//@ private represents svalid
}<br />
4.2 Konformität von Subtypen 412<br />
public void refill() {<br />
lo = cur;<br />
hi = Math.min( lo+buff.length, num );<br />
}<br />
public void close() {}<br />
//@ private depends state
4.2 Konformität von Subtypen 413<br />
Verhaltenskonformität bei Subtypen<br />
Bisher:<br />
• Spezifikationstechniken<br />
• Spezifikationsprobleme<br />
Weitergehendes Thema:<br />
• Was bedeutet es genau, dass sich ein Typ semantisch<br />
konform zu einem anderen verhält?<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 414<br />
Definition(konforme Subtypen):<br />
Ein Typ S ist ein (verhaltens-) konformer Subtyp von einem<br />
Typ T, wenn S-Objekte an allen wesentlichen Programmkontexten,<br />
an denen T-Objekten zulässig sind, die relevanten<br />
Eigenschaften von T-Objekten haben.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 415<br />
Problematik:<br />
• Was sind die wesentlichen Programmkontexte:<br />
x instanceof S<br />
• Was sind die relevanten Eigenschaften, wie sind sie<br />
formuliert:<br />
Information Hiding, Abstraktion, Effizienz<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 416<br />
Lösungsansatz:<br />
• Betrachte nur die Methodenschnittstelle, d.h. keine<br />
Konstruktoren, keine Information über den<br />
Implementierungstyp.<br />
• Gehe vom spezifizierten Verhalten aus, wobei bestimmte<br />
Ausführungsmodelle und Spezifikationstechniken zugrunde<br />
gelegt werden.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.2 Konformität von Subtypen 417<br />
Literatur:<br />
B. H. Liskov, J. M. Wing: A Behavioral Notion of<br />
Subtyping. Transactions on Programming Languages and<br />
Systems 16(6): 1811-1841 (1994).<br />
Bemerkung:<br />
• Das allgemeine Problem zur präzisen Spezifikation<br />
konformer Subtypbildung bzgl. Ausführungsmodellen wie<br />
in Java ist nicht gelöst.<br />
• Konforme Subtypbildung ist auch und gerade für die<br />
Komponentenprogrammierung von zentraler Bedeutung.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.3 Module und Modularität 418<br />
4.3 Module und Modularität<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.3 Module und Modularität 419<br />
Bisher haben wir Spezifikation auf Objekt- bzw. Klassenebene<br />
betrachtet. Hier werden zwei Aspekte angesprochen<br />
die über diese Ebene hinausgehen:<br />
4.3.1 Eigenschaften auf Modulebene<br />
4.3.2 modulare Spezifikation (vgl. Folie 178 )<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.3 Module und Modularität 420<br />
4.3.1 Eigenschaften auf Modulebene<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.3 Module und Modularität 421<br />
Ein objektorientiertes Modul besteht aus mehreren Klassen.<br />
Häufig gibt es Eigenschaften, die über Klassengrenzen<br />
hinausgehen.<br />
Modulinvarianten beschreiben Eigenschaften von<br />
Assoziationen, an denen Objekte mehrerer Klassen eines<br />
Moduls beteiligt sind.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.3 Module und Modularität 422<br />
Beispiel:<br />
Die Typen Component, Container, Window, etc. des Pakets<br />
java.awt erfüllen viele Invarianten, z.B.:<br />
• Ein Window-Objekt gehört zu keinem Container.<br />
• Ein Component-Objekt c gehört genau zu dem Container<br />
c.parent und zu keinem anderen Container.<br />
Bemerkung:<br />
Sprachkonstrukte und Techniken zur Spezifikation von<br />
Moduleigenschaften sind nur ansatzweise untersucht.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.3 Module und Modularität 423<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
4.3.2 Modulare Spezifikation
4.3 Module und Modularität 424<br />
Die Entwicklung modularer Spezifikations- und<br />
Verifikationstechniken ist von fundamentaler Bedeutung, da<br />
solche Techniken die Voraussetzung für Skalierbarkeit sind.<br />
Die Entwicklung modularer Techniken für die objektorientierte<br />
Programmierung steht noch am Anfang.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.3 Module und Modularität 425<br />
Modularität von Umgebungseigenschaften:<br />
Spezifikation durch Angabe der Variablen, die sich ändern<br />
dürfen.<br />
Problematik:<br />
• Sei m eine Methode in Modul P, die die Variable x ändern<br />
darf.<br />
• Sei y eine Variable in einem Modul Q, das P benutzt, so<br />
dass y in P nicht sichtbar ist, aber von x abhängig ist.<br />
Dann führt eine Änderung von x auch zu einer Änderung<br />
von y. Diese ist aber in P nicht erkennbar.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.3 Module und Modularität 426<br />
Beispiel(Modularität von Umgebungseigenschaften:):<br />
Wir benutzen eine Listenklasse, um eine Klasse für Mengen<br />
zu implementieren, d.h. wir stützen eine Abstraktionsebene<br />
auf eine andere ab:<br />
public abstract class List {<br />
/*@ public model non_null<br />
@ JMLObjectSequence listValue;<br />
@*/<br />
protected Node first, last;<br />
/*@ protected depends listValue
}<br />
4.3 Module und Modularität 427<br />
/*@ public normal_behavior<br />
@ requires o != null;<br />
@ modifies listValue;<br />
@ ensures listValue.equals(old(listValue.insertBack(o)));<br />
@*/<br />
public void append( Object o) {<br />
if (last==null) {<br />
first = new Node(null, null, o);<br />
last = first;<br />
} else {<br />
last.next = new Node(null, last, o);<br />
last = last.next;<br />
}<br />
}<br />
/* ... */<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
4.3 Module und Modularität 428<br />
public class Node {<br />
/*@ public model non_null<br />
@ JMLObjectSequence values;<br />
@*/<br />
public Node next, prev;<br />
public Object val;<br />
/*@ public depends values
4.3 Module und Modularität 429<br />
public abstract class Set {<br />
/*@ public model non_null<br />
@ JMLObjectSet setValue; @*/<br />
protected /*@ non_null @*/ List theList;<br />
/*@ protected depends setValue
4.3 Module und Modularität 430<br />
Abschließende Bemerkungen zu Kapitel 4:<br />
• Verschiedene Techniken zur Spezifikation von Programmund<br />
Schnittstelleneigenschaften<br />
• Problematik im Zusammenhang mit Subtypen<br />
• Testfälle können auch zur Spezifikation eingesetzt werden<br />
(JML erlaubt die Einbettung von Testfällen in<br />
Spezifikationen).<br />
• Am Ende des Entwicklungsprozesses bilden Spezifikation<br />
und Programm zwei Systembeschreibungen.<br />
• Verfeinerung von Spezifikation wurden nicht behandelt.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
5. Verifikation spezifizierter<br />
Eigenschaften
5. Verifikation spezifizierter Eigenschaften<br />
5.1 Techniken zur Verifikation<br />
5.2 Verifikation durch Beweis<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
432
Definition(Verifikation):<br />
Verifikation bedeutet den Nachweis, dass Software<br />
bestimmte, explizit beschriebene Eigenschaften besitzt.<br />
Beschreibung kann erfolgen durch:<br />
• Testfälle<br />
• Spezifikation der Funktionalität (Invarianten, Vor- und<br />
Nachbedingungen, ... )<br />
• Spezifikationen nicht-funktionaler Eigenschaften, z.B.<br />
Antwortzeiten, Codegröße, ... .<br />
Verifikation prüft also die Übereinstimmung von zwei<br />
expliziten Beschreibungen.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
433
5.1 Techniken zur Verifikation 434<br />
5.1 Techniken zur Verifikation<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
5.1 Techniken zur Verifikation 435<br />
Grundlegende Techniken zur Verifikation:<br />
• Testen mit Testfällen<br />
• Testen durch dynamisches Prüfen<br />
• erweitertes statisches Prüfen<br />
• Verifikation durch Beweis<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
5.1 Techniken zur Verifikation 436<br />
Testen mit Testfällen<br />
• Beschreibe das ,,Soll-Verhalten“ der Software durch eine<br />
(endliche) Menge von Eingabe-Ausgabe-Paaren bzw. von<br />
Paaren aus Eingaben und Zustandssequenzen.<br />
• Prüfe, ob die Software zu den Eingaben der Testfälle die<br />
entsprechenden Ausgaben liefert / Zustände durchläuft.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
5.1 Techniken zur Verifikation 437<br />
Vorteile:<br />
• Testfälle sind einfach zu verstehen; weitergehende<br />
Spezifikation ist nicht erforderlich.<br />
• Durchführung von Tests ist einfach.<br />
Nachteile:<br />
• Spezifikation ist immer unvollständig.<br />
• Problematik in der OO-Programmierung: Bestimmung der<br />
relevanten Objektgeflechte.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
5.1 Techniken zur Verifikation 438<br />
Testen durch dynamisches Prüfen<br />
• Beschreibe das ,,Soll-Verhalten“ der Software durch<br />
ausführbare Programmspezifikation.<br />
• Prüfe zur Laufzeit, ob die Spezifikation erfüllt ist.<br />
Dazu können beliebige Eingaben verwendet werden.<br />
Anders als beim Testen mit Testfällen wird also das<br />
Verhalten des Programms an bestimmten Stellen<br />
automatisch während der Auswertung geprüft.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
5.1 Techniken zur Verifikation 439<br />
Vorteile:<br />
• Fehlermeldung kann automatisiert und komfortabel<br />
gestaltet werden.<br />
• Gegenüber Testen mit Testfällen: Angabe des<br />
Ausgabeverhaltens ist nicht notwendig.<br />
• Gegenüber statischen Verfahren: Einfacher zu handhaben.<br />
Nachteile:<br />
• Gegenüber Testfällen: Spezifikation muss vorhanden sein<br />
und ist fehleranfälliger als Testfälle.<br />
• Gegenüber Verifikation durch Beweis: Unvollständigkeit<br />
und schwächere Spezifikationen.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
5.1 Techniken zur Verifikation 440<br />
Erweitertes statisches Prüfen<br />
• Beschreibe das ,,Soll-Verhalten“ der Software durch<br />
Programmspezifikation.<br />
• Nutze alle automatische Prüftechniken zur statischen<br />
Analyse der Konsistenz von Programm und Spezifikation.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
5.1 Techniken zur Verifikation 441<br />
Vorteile:<br />
• Gegenüber Testen: Vollständigere Abdeckung des<br />
Verhaltens; mächtigere Spezifikationen möglich.<br />
• Gegenüber Verifikation durch Beweis: Einfacher zu<br />
handhaben, weil vollautomatisch.<br />
Nachteile:<br />
• Gegenüber Testen: Spezifikation muss höheren<br />
Ansprüchen genügen, insbesondere reichen isolierte<br />
Eigenschaften im Allg. nicht aus.<br />
• Gegenüber Verifikation durch Beweis: Unvollständigkeit<br />
und schwächere Spezifikationen.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
5.1 Techniken zur Verifikation 442<br />
Erweitertes statisches Prüfen basiert auf recht unterschiedlichen<br />
Techniken:<br />
• statischer Daten- und Kontrollflussanalyse<br />
• Modellprüfung endl. Zustandsräume (model checking)<br />
• Automatisierung klassischer Programmbeweistechniken<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
5.1 Techniken zur Verifikation 443<br />
• siehe nächsten Abschnitt<br />
Verifikation durch Beweis<br />
Bemerkung:<br />
Die unterschiedlichen Verifikationstechniken ergänzen sich<br />
und können kombiniert werden.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
5.2 Verifikation durch Beweis 444<br />
5.2 Verifikation durch Beweis<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
5.2 Verifikation durch Beweis 445<br />
Verifikation im engeren Sinne bedeutet den Beweis<br />
spezifizierter Eigenschaften mit logischen Mitteln.<br />
Im Gegensatz zum Testen erlaubt Verifikation durch Beweis,<br />
die Korrektheit zu zeigen, d.h. insbesondere die Abwesenheit<br />
von Fehlern.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
5.2 Verifikation durch Beweis 446<br />
Prinzipieller Ansatz<br />
• Grundlage für die Beweise ist ein mathematisches oder<br />
formal-logisches Spezifikations- und<br />
Verifikationsframework.<br />
•<br />
Übersetze Spezifikationen und Programme in die Formeln<br />
des Framework.<br />
• Beweise die resultierenden Beweisverpflichtungen.<br />
Wir erläutern den Ansatz anhand eines Frameworks auf der<br />
Basis einer Hoare-Logikerweiterung.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
5.2 Verifikation durch Beweis 447<br />
Spezifikations- und Verifikationsframework<br />
Als logische Grundlage betrachten wir eine sortierte<br />
Prädikatenlogik mit algebraischen Datentypen (vgl.<br />
Abschnitt 1.2 ).<br />
Die statische Semantik der betrachteten Programmiersprache<br />
wird damit spezifiziert (vgl. Abschn. 2.2.2 ).<br />
Auf dieser Basis lassen sich Eigenschaften über Programmzustände<br />
formulieren.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
5.2 Verifikation durch Beweis 448<br />
Programmspezifikationen:<br />
• Invariante zum Typ T ( inv[T] )<br />
• Vor- und Nachbedingungsspezifikation zur Methode m in<br />
Typ T ( req[T:m], ens[T:m] )<br />
• Veränderungsklauseln ( mod[T:m] )<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
5.2 Verifikation durch Beweis 449<br />
Programmlogik:<br />
• Hoare-Logik für partielle Korrektheit mit zusätzlichen<br />
Regeln für OO-Konstrukte<br />
• Formeln sind Tripel { P } c { Q }, wobei<br />
◦ P, Q Formeln der Prädikatenlogik sind;<br />
◦ c eine Anweisung, virtuelle Methode oder Methodenimplementierung<br />
ist.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
5.2 Verifikation durch Beweis 450<br />
Definition(Methodenimplementierung):<br />
Eine Methodenimplementierung K@m ist eine Deklaration<br />
einer Methode mit Rumpf in Klasse K.<br />
Definition(virtuelle Methode):<br />
Zu jeder dynamisch zu bindenden Methode m, die ein Typ T<br />
selbst deklariert oder erbt, führen wir eine virtuelle Methode<br />
T:m ein, die das Verhalten aller Methoden m in Subtypen<br />
von T zusammenfasst.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
5.2 Verifikation durch Beweis 451<br />
Umsetzung von Programmspezifikationen<br />
Die Spezifikation eines vollständigen Programms Π wird<br />
umgesetzt in eine Menge von Tripeln. Seien:<br />
• S0 ein Typ,<br />
• m eine Methode in S0 und<br />
• S1, ..., Sk die Supertypen von S0, in denen m existiert,<br />
mit Si < Si+1<br />
• T = { T | T ist Typ in Π }<br />
• INV ⇔ <br />
T ∈T inv[T]<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
5.2 Verifikation durch Beweis 452<br />
Für S0:m ist zu zeigen:<br />
{ INV ∧ <br />
0≤i≤k req[Si:m] } S0:m { INV }<br />
{ INV ∧ <br />
0≤i≤k req[Si:m] } S0:m { <br />
0≤i≤k ens[Si:m] }<br />
sowie<br />
down(mod[Si:m]) ⊆ down(mod[Si+1:m])<br />
{ INV ∧ <br />
0≤i≤k req[Si:m] ∧ v /∈ down(mod[Sk:m]) ∧ v = Z }<br />
S0:m { v = Z }<br />
wobei down( vl: set of VAR ) die Menge aller Variablen<br />
bezeichnet, die abhängige Variablen in vl besitzen.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
5.2 Verifikation durch Beweis 453<br />
Bemerkung:<br />
Details der Umsetzung hängen sowohl von der<br />
Spezifikationssprache als auch von der verwendeten<br />
Programmlogik ab.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
5.2 Verifikation durch Beweis 454<br />
Hoare-Logik für objektorientierte Programme<br />
Zusätzlich zu den Eigenschaften für klassische prozedurale<br />
Programme muss eine Logik für moderne objektorientierte<br />
Programme mit Folgendem umgehen können:<br />
• dynamisch allozierte Objekte<br />
• Subtyping<br />
• dynamische Bindung<br />
• Ausnahmebehandlung<br />
Wir illustrieren diese Aspekte an ausgewählten Regeln für<br />
eine Teilsprache von Java.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
5.2 Verifikation durch Beweis 455<br />
Axiom für Leseanweisung:<br />
{(y = null ∧ P [$(y.a)/x]) ∨<br />
(y = null ∧ P [$〈NullP Exc〉/$, new($, NullP Exc)/exc])}<br />
x = y.a; {P }<br />
Regel für Sequenzanweisung:<br />
{P} s1 {(exc = null ∧ Q) ∨ (exc = null ∧ R)}<br />
{R} s2 {Q}<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03<br />
{P} s1 s2 {Q}
5.2 Verifikation durch Beweis 456<br />
Regeln für Methodenaufruf:<br />
{P} vm(styp(y, x = y.m(e); ), m) {Q[res/x]}<br />
{(y = null ∧ P[y/this, e/par])∨<br />
(y = null ∧ Q[$〈NullPExc〉/$, new($, NullPExc)/exc])}<br />
x = y.m(e); {Q}<br />
{P } x = y.m(e); {Q}<br />
{P [w/Z]} x = y.m(e); {Q[w/Z]}<br />
wobei w eine Programmvariable ungleich x ist und Z eine<br />
logische Variable.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
5.2 Verifikation durch Beweis 457<br />
Bemerkung:<br />
• Obige Regeln sollen wichtige Ideen demonstrieren. Auf<br />
Details und die Behandlung rekursiver Methoden muss hier<br />
verzichtet werden.<br />
• Die Korrektheit der Logik kann bzgl. der operationalen<br />
Semantik gezeigt werden.<br />
A. Poetzsch-Heffter: FASOOP Wintersemester 02/03
6. Ausblicke
• Die Entwicklung der vorgestellten Techniken ist noch im<br />
Gange:<br />
◦ Integration<br />
◦ Modulebene<br />
◦ Modularität<br />
• Wichtige zukünftige Aspekte sind außerdem:<br />
◦ Zusammenwirken mit Entwicklungsmethode<br />
◦ Integration mit Entwurfstechniken<br />
◦ Werkzeug- und weitere Sprachunterstützung<br />
MMISS: Kurztitel September 15, 2003<br />
459