Liaison de fonction dynamique (ou pas)
Voir aussi : vidéo peertube - vidéo youtube - dépôt git
Comment appeler des fonctions sur des collections hétérogènes. Exemple : type Forme + sous-types Carre et Rectangle, fonctions surface.
Duck typing
- appeler une fonction existante mais différente selon le type (
formes_duck-typing.py
) :
#!/usr/bin/env python3
class Carre:
def __init__(self, c):
self.c = c
def surface(self):
return self.c * self.c
class Rectangle:
def __init__(self, w, h):
self.w = w
self.h = h
def surface(self):
return self.w * self.h
= [Carre(2), Rectangle(2, 3)]
formes
for f in formes:
# duck typing :
# appelle la méthode surface de Carre ou de Rectangle, selon le type de f
print(f.surface())
Introspection
- tester si la valeur possède une méthode donnée (
formes_introspection.py
) :
#!/usr/bin/env python3
class Carre:
def __init__(self, c):
self.c = c
def surface(self):
return self.c * self.c
class Rectangle:
def __init__(self, w, h):
self.w = w
self.h = h
def surface(self):
return self.w * self.h
= [Carre(2), Rectangle(2, 3), 42]
formes
for f in formes:
# introspection : teste si surface est une méthode de f
if 'surface' in dir(f):
print(f.surface())
Typage dynamique
- tester le type de la valeur (
formes_typage-dynamique.py
) :
#!/usr/bin/env python3
class Carre:
def __init__(self, c):
self.c = c
def surfaceCarre(self):
return self.c * self.c
class Rectangle:
def __init__(self, w, h):
self.w = w
self.h = h
def surfaceRectangle(self):
return self.w * self.h
= [Carre(2), Rectangle(2, 3), 42]
formes
for f in formes:
# typage dynamique :
# teste si f est de type Rectangle
if isinstance(f, Rectangle):
print(f.surfaceRectangle())
# teste si f est de type Carre
if isinstance(f, Carre):
print(f.surfaceCarre())
Multiple dispatch / multiméthodes
- appelle la fonction correspondant aux paramètres donnés (
formes_multiple-dispatch.jl
) :
#!/usr/bin/env julia
struct Carre
:: Int
c end
struct Rectangle
:: Int
w :: Int
h end
# définition multiple de fonction
surface(f :: Carre) = f.c * f.c
surface(f :: Rectangle) = f.w * f.h
surface(f1 :: Carre, f2 :: Rectangle) = surface(f1) + surface(f2)
= [Carre(2), Rectangle(2, 3)]
formes
# multiple dispatch :
# appelle la fonction correspondant aux paramètres
for f in formes
println(surface(f))
end
println(surface(Carre(2), Rectangle(2, 3)))
Héritage avec fonctions virtuelles
- appelle une méthode définie pour le type et spécialisé dans les sous-types (
formes_fonctions-virtuelles.cpp
) :
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
// type principal
struct Forme {
// méthode redéfinie dans les sous-types
virtual double surface() const = 0;
};
struct Carre : Forme {
double _c;
(double c) : _c(c) {}
Carredouble surface() const override { return _c * _c; }
};
struct Rectangle : Forme {
double _w, _h;
(double w, double h) : _w(w), _h(h) {}
Rectangledouble surface() const override { return _w * _h; }
};
int main() {
// collection de Carre/Rectangle
<unique_ptr<Forme>> formes;
vector.push_back(make_unique<Carre>(2));
formes.push_back(make_unique<Rectangle>(2, 3));
formes
for (const auto & f : formes) {
// appelle la méthode correspondant au sous-type
<< f->surface() << endl;
cout }
return 0;
}
En Haskell
- types dynamiques : type universel + fonctions de traitement (
formes_dynamic.hs
) :
import Data.Dynamic
data Carre = Carre Double
surfaceCarre :: Carre -> Double
Carre c) = c*c
surfaceCarre (
data Rectangle = Rectangle Double Double
surfaceRectangle :: Rectangle -> Double
Rectangle w h) = w*h
surfaceRectangle (
-- liste hétérogène (Dynamic représente le type universel)
formes :: [Dynamic]
= [ toDyn (Carre 2), toDyn (Rectangle 2 3) ]
formes
-- calcule la surface d'une valeur inclu dans un Dynamic, si possible
dynToSurface :: Dynamic -> Maybe Double
= case fromDynamic x :: Maybe Carre of
dynToSurface x Just c -> Just $ surfaceCarre c
Nothing -> case fromDynamic x :: Maybe Rectangle of
Just r -> Just $ surfaceRectangle r
Nothing -> Nothing
= print (map dynToSurface formes) main
- types existentiels : classe et types classiques + type générique (
formes_types-existentiels.hs
) :
{-# LANGUAGE ExistentialQuantification #-}
class Surfacable a where
surface :: a -> Double
data Carre = Carre Double
instance Surfacable Carre where
Carre c) = c*c
surface (
data Rectangle = Rectangle Double Double
instance Surfacable Rectangle where
Rectangle w h) = w*h
surface (
-- type existentiel :
-- empaquette des données de classe Surfacable
data MkSurfacable = forall a . (Surfacable a) => MkSurfacable a
-- instancie la classe Surfacable pour le type existentiel (pas obligatoire)
instance Surfacable MkSurfacable where
MkSurfacable x) = surface x
surface (
-- liste hétérogène de valeurs de classe Surfacable
surfacables :: [MkSurfacable]
= [ MkSurfacable (Carre 2), MkSurfacable (Rectangle 2 3) ]
surfacables
= do
main -- avec instance de Surfacable
print $ map surface surfacables
-- sans instance de Surfacable
print $ map (\(MkSurfacable x) -> surface x) surfacables
- types algébriques (statique) : type classique + fonction traitant toutes les valeurs possibles (
formes_types-algebriques.hs
) :
-- type algébrique
data Forme = Carre Double
| Rectangle Double Double
-- fonction traitant toutes les valeurs possibles du type
surface :: Forme -> Double
Carre c) = c*c
surface (Rectangle w h) = w*h
surface (
formes :: [Forme]
= [Carre 2, Rectangle 2 3]
formes
= print $ map surface formes main