vidéo peertube - vidéo youtube - dépôt git
Liaison de fonction dynamique (ou pas)
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
formes = [Carre(2), Rectangle(2, 3)]
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
formes = [Carre(2), Rectangle(2, 3), 42]
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
formes = [Carre(2), Rectangle(2, 3), 42]
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
c :: Int
end
struct Rectangle
w :: Int
h :: Int
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)
formes = [Carre(2), Rectangle(2, 3)]
# 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;
Carre(double c) : _c(c) {}
double surface() const override { return _c * _c; }
};
struct Rectangle : Forme {
double _w, _h;
Rectangle(double w, double h) : _w(w), _h(h) {}
double surface() const override { return _w * _h; }
};
int main() {
// collection de Carre/Rectangle
vector<unique_ptr<Forme>> formes;
formes.push_back(make_unique<Carre>(2));
formes.push_back(make_unique<Rectangle>(2, 3));
for (const auto & f : formes) {
// appelle la méthode correspondant au sous-type
cout << f->surface() << endl;
}
return 0;
}
En Haskell
- types dynamiques : type universel + fonctions de traitement (
formes_dynamic.hs
) :
import Data.Dynamic
data Carre = Carre Double
surfaceCarre :: Carre -> Double
surfaceCarre (Carre c) = c*c
data Rectangle = Rectangle Double Double
surfaceRectangle :: Rectangle -> Double
surfaceRectangle (Rectangle w h) = w*h
-- liste hétérogène (Dynamic représente le type universel)
formes :: [Dynamic]
formes = [ toDyn (Carre 2), toDyn (Rectangle 2 3) ]
-- calcule la surface d'une valeur inclu dans un Dynamic, si possible
dynToSurface :: Dynamic -> Maybe Double
dynToSurface x = case fromDynamic x :: Maybe Carre of
Just c -> Just $ surfaceCarre c
Nothing -> case fromDynamic x :: Maybe Rectangle of
Just r -> Just $ surfaceRectangle r
Nothing -> Nothing
main = print (map dynToSurface formes)
- 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
surface (Carre c) = c*c
data Rectangle = Rectangle Double Double
instance Surfacable Rectangle where
surface (Rectangle w h) = w*h
-- 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
surface (MkSurfacable x) = surface x
-- liste hétérogène de valeurs de classe Surfacable
surfacables :: [MkSurfacable]
surfacables = [ MkSurfacable (Carre 2), MkSurfacable (Rectangle 2 3) ]
main = do
-- 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
) :