• Aucun résultat trouvé

Programmation Orient´ee Objet Sous-typage M´ethodes Interfaces Dispatch dynamique H´eritage

N/A
N/A
Protected

Academic year: 2022

Partager "Programmation Orient´ee Objet Sous-typage M´ethodes Interfaces Dispatch dynamique H´eritage"

Copied!
23
0
0

Texte intégral

(1)

Programmation Orient ´ee Objet

Sous-typage M ´ethodes Interfaces

Dispatch dynamique H ´eritage

(2)

Sous-typage

Aussi parfois appel ´e polymorphisme ad-hoc

Possibilit ´e de passer des arguments de plusieurs types Distinction entre type statique et type dynamique:

Type dynamique = type d’une valeur

Type statique = type d’une variable

Coh ´erence: Type-Dynamique

<

Type-Statique Type = ensemble de contraintes

Sous-typage correspond `a inclusion de contraintes

(3)

Sous-typage sur les structs

struct parent { shape *a; t2 b; }

Sous-typage en largeur, lorsqu’un struct est un pr ´efixe d’un autre:

struct fille { shape *a; t2 b; t3 c; }

Sous-typage en profondeur, lorsqu’un champ est un sous-type:

struct fils { square *a; t2 b; }

(4)

Pourquoi le sous-typage

Le sous-typage peut ˆetre vu comme r ´esultat pragmatique!

Acc `es `a un object de type

parent

se traduisent par

LOAD Rd <- 8(Rs) ;; x->a

et

LOAD Rd <- 16(Rs) ;; x->b

N’importe quel type o `u

x->a

et

x->b

se traduisent de la m ˆeme mani `ere peut ˆetre consid ´er ´e un sous-type de

parent

= ⇒

¡¡ Une autre traduction m `ene `a une autre notion de sous-typage !!

[ Ou vice-versa! en tout cas: ad-hoc! ]

(5)

Covariance / Contravariance

Pour que

f

1

: A

1

→ B

1 puisse s’utiliser

n’importe o `u o `u

f

2

: A

2

→ B

2 est accept ´ee elle doit:

accepter n’importe quel argument accept ´e par

f

2

renvoyer des valeurs accept ´ees par n’importe quel appelant de

f

2

Les arguments de fonctions sont donc naturellement contravariants:

A

2

≤ A

1

B

1

≤ B

2

A

1

→ B

1

≤ A

2

→ B

2

(6)

Sous-typage en profondeur et mutabilit ´e

Le sous-typage en profondeur est incompatible avec la mutabilit ´e:

struct parent { shape *s; } struct enfant { square *s; }

void set_s (parent *p, shape *s) { p->s = s; }

void probl` eme (enfant *e, shape *s) { set_s (e, s); }

L’affectation

e->s = s;

serait (correctement) rejet ´ee!

On dit que les champs mutables doivent ˆetre invariants

(7)

Interface

Une interface sp ´ecifie les contraintes d’un type

Typiquement: liste de m ´ethodes avec leurs signatures

parfois inclus: des champs que l’objet doit avoir, avec leurs types Donc, une interface est en fait une sorte de type

On dit qu’un type impl ´emente une interface

Peut se faire apr `es-coup, s ´epar ´ement de la d ´efinition du type

(8)

H ´eritage

Souvent confondu avec le sous-typage Technique de d ´eclaration de nouveau type

Type d ´ecrit par des ajouts `a un type existant

R ´eutilisation des champs et m ´ethodes du type parent Parfois la seule mani `ere de d ´efinir un sous-type

Ne d ´efini pas forc ´ement un sous-type

Controvers ´e: D ´ependance forte entre le sur-type et le sous-type

(9)

Classes

Une classe d ´ecrit un type ainsi qu’un ensemble de m ´ethodes

La classe et son type sont souvent utilis ´es indistinctement

La classe existe aussi `a l’ex ´ecution

A l’ex ´ecution, une classe est un objet qui peut contenir:`

La table des m ´ethodes

Un ensemble de champs: les “attributs de classe”

Etant un objet, on peut lui associer une classe: la´ m ´etaclasse

(10)

Dispatch dynamique

Un appel de m ´ethode choisi la m ´ethode selon l’objet

Chaque appel peut ex ´ecuter un code diff ´erent `a chaque fois Aussi parfois appel ´e polymorphisme ad-hoc

(11)

M ´ethodes

Une m ´ethode est une sorte de fonction associ ´ee `a un objet:

x.method (arg1, arg2);

Ex ´ecute la m ´ethode

method

associ ´ee `a l’objet

x

Se traduit g ´en ´eralement en un appel de fonction:

funcall (lookup (x, method), x, arg1, arg2)

O `u la fonction qui impl ´emente

method

a un argument suppl ´ementaire nomm ´e

self

ou

this

(12)

Table des m ´ethodes

La magie est donc dans:

lookup (x, method)

Impl ´ementation “classique”:

lookup (x, method) = x->class->method

Chaque objet a un champ cach ´e

class

`a une position constante

class

contient la table des m ´ethodes (parfois appel ´ee vtable) Chaque m ´ethode a une position connue d’avance dans la vtable

LOAD Rc <- 0(Rs) ;; 0 = offset de "class"

LOAD Rf <- M(Rc) ;; M = offset de "method"

(13)

Types des classes et instances

class A { a : int; method m1 (int); } class B { a : int; b : float;

method m1 (int); method m2 (string); }

Ces d ´eclarations cr ´eent 4 types d’objets:

A class

= (

class

:

metaclass

,

m1

:

int

void

)

B class

= (

class

:

metaclass

,

m1

:

int

void

,

m2

:

string

void

)

A inst

= (

class

:

A class

,

a

:

int

)

B inst

= (

class

:

B class

,

a

:

int

,

b

:

float

)

(14)

Types des classes et instances (corr.)

class A { a : int; method m1 (int); } class B { a : int; b : float;

method m1 (int); method m2 (string); }

Ces d ´eclarations cr ´eent 4 types d’objets:

A class

= (

class

:

metaclass

,

m1

:

A inst

int

void

)

B class

= (

class

:

metaclass

,

m1

:

B inst

int

void

, ...)

A inst

= (

class

:

A class

,

a

:

int

)

B inst

= (

class

:

B class

,

a

:

int

,

b

:

float

)

B class

6≤

A class (pour raisons de contravariance) B inst

A inst (par ¿magie?)

(15)

Classes de type

Programmation orient ´ee objet en Haskell Cousin des interfaces de Java:

class Drawable a where

draw :: Display → aIO ()

Sp ´ecifie les m ´ethodes que les instances doivent fournir Peut fournir des impl ´ementation par d ´efaut

draw :: Drawable a ⇒ DisplayaIO ()

(16)

Instances de classes de type

Les instances sont d ´efinies s ´epar ´ement du type correspondant:

instance Drawable Square where

draw :: Display → SquareIO () draw s d = ...

instance Drawable Circle where

draw :: Display → CircleIO () draw c d = ...

On peut donc les d ´efinir longtemps apr `es avoir d ´efini Square

(17)

Exemple: listes num ´eriques

instance Num a => Num [a] where x + y = zipWith (+) x y

x * y = zipWith (*) x y negate x = map negate x signum x = map signum x abs x = map abs x

fromInteger n = nlist

where nlist = fromInteger n : nlist

et ainsi:

[1, 2, 3] + 6 = ⇒ [7, 8, 9]

(18)

Contraintes sur les types

Les classes sont des contraintes sur les types

dist :: (Ord a, Num a) => a -> a -> a

dist x y = if x > y then x - y else y - x

Une classe de type peut h ´eriter d’un (ou plusieurs) autres

classe (Ord a, Num a) => OrdNum a where ...

alors

dist :: OrdNum a => a -> a -> a

dist x y = if x > y then x - y else y - x

(19)

Contraintes sur des types “impropres”

Int

et

Maybe Int

sont des proper types

Maybe

est un constructeur de type: sorte de fonction sur les types Les classes de types se g ´en ´eralisent aux constructor classes

class Functor f where

fmap :: (a -> b) -> f a -> f b instance Functor [] where

fmap = map

instance Functor Maybe where

(20)

D ´el ´egation

Champs dans les instances, m ´ethodes dans la classe

trop restrictif!

Remplace le champ cach ´e

class

par le champ cach ´e

parent lookup (x, method) =

if (method existe dans x) return x.method;

else

lookup (x->parent, method);

Et ce m ˆeme

lookup

est utilis ´e pour les champs!

Champs et m ´ethodes: m ˆeme combat!

Unifie aussi classes et instances!

(21)

Table dans la m ´ethode: Multi-m ´ethodes

Autre d ´efinition possible de

lookup

:

lookup (x, method) =

gethash (method->table, typeof (x))

Utilis ´e en Common Lisp:

(method x arg1 arg2)

Se g ´en ´eralise `a plusieurs arguments:

(defmethod add ((x int) (y int)) ...)

(defmethod add ((x string) (y string)) ...)

(defmethod add ((x string) y) ...)

(22)

Table de m ´ethodes flottante: Type classes

Haskell manipules ses vtables (dictionnaires) s ´epar ´ement des objets!

min :: Ord a => a -> a -> a min x y | x < y = x

| otherwise = y

Est transform ´e par le compilateur en

min :: OrdDict a -> a -> a -> a min dict x y | dict.< x y = x

| otherwise = y

Note: le dictionnaire n’appartient ni `a

x

ni `a

y

sum :: Num a => [a] -> a

Un seul dictionnaire!

(23)

Avantages/inconv ´enients des types classes

Pas besoin de champs class dans les objets

Applicable aux Int, Bool, aux types fonctions, ...

Bonne interaction avec l’inf ´erence de types

Dispatch sans valeur:

read :: Read a => String -> a

Impossible d’avoir deux m ´ethodes diff ´erentes avec le m ˆeme nom

Drawable a => [a]

est une liste homog `ene!

Pour obtenir des structures h ´et ´erog `enes, il faut passer par

data DrawableElem =

Références

Documents relatifs

Par exemple : std::string , qui obligatoirement doit faire des allocations de mémoire (pour stocker les caractères) et donc libérer, quoi qu'il arrive, même en cas d'exception

Plusieurs instances de cette classe devront référencer le même objet en mémoire : définition d'une sous-classe assistante, associant l'adresse réelle de l'objet et un compteur...

Une pile représente un ensemble de données où l'on ne peut accéder qu'au dernier élément entré, qui devient donc le premier à sortir. On les appelle parfois LIFO (last in

A présent le code peut s'utiliser pour afficher tous les éléments d'une liste d'entiers différents de -5, tous les éléments d'un tableau de chaînes de moins de trois

sinon si valeur dans feuille courante &lt; valeur à ajouter Prend branche gauche comme nouvelle racine Ajout. sinon si valeur dans feuille courante &gt; valeur à ajouter Prend

parenthèse ouvrante : on remarque que l'utilisation d'une pile peut simplifier la gestion des parenthèses pour la construction de l'arbre..... 15

• Arbre de recherche suivant la valeur Facile à programmer Très rapide à chercher Espace mémoire moyen Aucune n'est préférable, le contexte. décidera de la

Accès aux membres Modes d’héritage Amitié et héritage Surcharge de méthodes..