Fortgeschrittene Aspekte objektorientierter Programmierung

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