1 Typsystem (III): Polymorphie

Werbung
2 Polymorphe Typsysteme
alp3-2.1
1
Zur Erinnerung (Programmiersprachen-Terminologie):
$ Vereinbarung (declaration):
ein benanntes Programmelement wird eingeführt.
$ Dessen Name (identifier) soll die eindeutige Bezugnahme
auf dieses Programmelement ermöglichen
(innerhalb seines Sichtbarkeitsbereichs!).
$ Konsequenz: Verbot von Namenskollisionen.
Abschwächung dieses Verbots  Polymorphie
alp3-2.1
2
Polymorphie (polymorphism; griech. „Vielgestaltigkeit“)
ist Eigenschaft einer Programmiersprache bzw. ihres Typsystems:
Bei einem Prozeduraufruf (Methodenaufruf, Funktionsaufruf, ...)
werden zur Identifikation der Prozedur neben dem Namen
auch die Typen der involvierten Daten herangezogen.
alp3-2.1
3
Polymorphie
Überladen
(overloading)
ad-hoc
(Java, ...)
alp3-2.1
geplant
(Haskell, ...)
Universelle Polymorphie
(universal polymorphism)
parametrische P.
Einschluss-P.
(parametric p.),
(inclusion p.)
(Haskell, Java, ...)
(Java, ...)
Generizität
bei Vererbung
4
2.1 Überladen
(vgl. ALP II - 6.2)
Beispiele:
1234 + 4711
"über" + "laden"
1000 + "fach"
Addition
Konkatenation
Konkatenation nach Typanpassung
boolean big(int i)
{return Math.abs(i)>=10000; }
boolean big(String s){return s.compareTo("zzzzz")>0;}
... big("123") || big(123) ...
void test(A a) { ... }
void test(B b) { ... }
... test(new A()); test(new B()); ...
alp3-2.1
5
Signatur eines Klassenelements:
- Name bzw.
- Name samt Anzahl und Typen der Argumente (bei Methode)
Beispiel:
float power(float x, int i) { ... }
hat Signatur power(float,int)
Elemente einer Klasse müssen verschiedene Signaturen haben.
(Diese Regel schwächt das Kollisionsverbot für Namen ab.)
Überladen (overloading) eines Namens liegt vor, wenn es mehrere
gleichnamige Elemente mit verschiedenen Signaturen gibt.
Achtung: nicht verwechseln mit Ersetzen (overriding) in einer Unterklasse!
(ALP II - 10.3)
alp3-2.1
6
Beispiel - die folgende Klasse ist fast korrekt:
class
static
static
static
static
static
}
neg {
int neg = -1;
void neg(){neg = neg(neg);}
int neg(int x){return -x;}
int neg(float x){return -(int)x;}
float neg(float x){return -x;}// collides
? Welches Element ist gemeint, wenn der Name neg benutzt wird ?
Z.B. ... neg = neg(neg); ...
alp3-2.1
??
7
... neg ... ?
1.
Überladen wird statisch (!) aufgelöst:
Falls keine öffnende Klammer folgt: Variable.
[Fehler, falls keine solche Variable sichtbar.]
2. Sonst bei n Argumenten: Methode mit n Argumenten und
passenden* Argumenttypen, sofern es genau eine solche gibt.
[Fehler, falls keine solche Methode sichtbar.]
3. Falls mehrere solche: die „spezifischste Methode“
(d.h. verwirf jede solche Methode, zu der es eine andere
solche Methode gibt, deren Argumenttypen verträglich
mit den Argumenttypen jener Methode sind).
[Fehler, falls diese Methode nicht eindeutig bestimmbar.]
alp3-2.1
* Typverträglichkeit!
8
Beispiel 1:
...
static void neg(){neg = neg(neg);}
...
int neg (1.)
int neg(int x)
Beispiel 2:
n
void m(short s, int i) o
void m(int i,
 n
m(by,in) Â o
m(in,ch)
char c)
(3.)
int
short char
byte
 falsch, weil weder n noch o passt (2.)
m(by,ch) Â falsch, weil sowohl n als auch o passt (3.)
m(ch,by)
alp3-2.1
9
Zur Erinnerung: Überladen in Haskell ?
$ mit jedem Funktionsnamen ist ein bestimmter Funktionstyp
- die Signatur - verbunden (evtl. polymorph!)
$ die Signatur beinhaltet auch den Ergebnistyp
$ ad-hoc-Überladen wie in Java ist nicht vorgesehen
$ aber eingeschränkt geplantes Überladen mit Typklassen
Beispiel:
power :: Double -> Int -> Double
power x i = if i==0 then 1 else x * power x (i-1)
kollidiert mit
power x i = x ++ show i
(Signatur Show a => [Char] -> a -> [Char] )
alp3-2.1
Was tun?
10
class Power t where
power :: t -> Int -> t
( t ist „formaler Typparameter“ )
instance Power Double where
(... hier durch Double aktualisiert)
power x i = if i==0 then 1 else x * power x (i-1)
data Text = Str [Char]
deriving Show
instance Power Text where
(... hier durch Text aktualisiert)
power(Str x)i = Str(x ++ show i)
(
alp3-2.1
power(Str "abc")3 liefert Str "abc3" )
11
Herunterladen