Exercices avancés sur la généricité.
Fraise
, Banane
et Orange
et leur super-classe Fruit
. Comme on peut peler les bananes et les oranges (mais pas les fraises), on ajoute une super-classe commune FruitAPeler
.exemple_banane
(il devrait fonctionner).// Pseudocode. Ajoutez les casts qui vont bien si nécessaires.
void exemple_banane() {
// Créer une brochette de fruits.
Brochette brochette = new Brochette();
// Créer une banane.
Banane banane = new Banane();
// Embrocher la banane.
brochette.embrocher(banane);
// Débrocher un fruit.
FruitAPeler f = brochette.debrocher();
// Peler le fruit débroché.
f.peler()
}
exemple_fruit
mais qui prend un fruit en paramètre:// Pseudocode. Ajoutez les casts qui vont bien si nécessaires.
void exemple_fruit(Fruit fruit) {
// Créer une brochette de fruits.
Brochette brochette = new Brochette();
// Embrocher le fruit
brochette.embrocher(fruit);
// Débrocher un fruit.
FruitAPeler f = brochette.debrocher();
// Peler le fruit débroché.
f.peler()
}
exemple_banane
, invoque exemple_fruit
avec une instance de banane, puis invoque exemple_fruit
avec une instance de fraise.Ici on a deux morceaux de code très similaires exemple_banane
et exemple_fruit
.
Le premier est systématiquement fonctionnel: il ne peut pas échouer lors de l'exécution.
Le second est partiellement fonctionnel: il y a un risque d'échec fondamental car dans notre modèle (plus ou moins réaliste), il est impossible de peler une fraise, quelque soit la façon dont on s'y prend.
Pour chacun des langages:
exemple_banane
d'un point de vu de la verbosité et de la sûreté des types ?exemple_fruit
) ?BrochetteGen
bornée par Fruit
.exemple_banane_p
et exemple_fruit_p
en utilisant BrochetteGen<FruitAPeler>
au lieu de Brochette
.exemple_fruit_p
) ?BrochetteGen<Fruit>
au lieu de BrochetteGen<FruitAPeler>
quels problèmes aurait été résolus/non-résolus (par rapport à la version non-générique) ?Cette fois-ci on fait varier le type générique.
On utilise statiquement une BrochetteGen<Fruit>
et dynamiquement une BrochetteGen<FruitAPeler>
Ce qui donne le pseudo-code suivant
void brochette_fp_fruit(Fruit fruit) {
// Pseudocode. Ajoutez les casts qui vont bien.
BrochetteGen<FruitAPeler> brochette_p = new BrochetteGen<FruitAPeler>();
BrochetteGen<Fruit> brochette_f = brochette_p;
brochette_f.embrocher(fruit);
brochette_p.debrocher().peler();
}
brochette_fp_fruit
avec une banane puis une fraise.brochette_fp_fruit
dans les 4 langages Java, C++, C# et NitChacun de ces 4 langages a une sémantique différente par rapport au sous-typage et à la généricité.
On continue maintenant de regarder les problèmes de sous-typage des brochettes par rapport aux variations génériques. Pour ce faire, développe des fonction (méthodes/sous-programmes) utilitaires qui acceptent des brochettes passées en paramètre.
Réalisez ces fonctions dans les langages Java, C++, C# et Nit en utilisant en paramètre des BrochetteGen
(des types génériques).
Réalisez l'équivalent en Python (ou Ruby) en utilisant Brochette
la version non générique de la classe.
?
, extends
et super
.BrochetteGen
: voir in
et out
.Créez une fonction (méthode statique ou fonction hors classe) compte_sloubifuit
:
BrochetteGen<Fruit>
qu'avec une BrochetteGen<Banane>
.Quel est le "meilleur" type statique du paramètre de la fonction compte_sloubifuit
pour le langage considéré ?
// idéalement on veut pouvoir écrire un truc du genre:
BrochetteGen<Fruit> bf = new BrochetteGen<Fruit>();
// embrochage de fruits variés dans bf.
compte_sloubifuit(bf);
// mais aussi quelque chose du genre
BrochetteGen<FruitAPeler> bp = new BrochetteGen<FruitAPeler>();
// embrochage de fruits variés dans bp.
compte_sloubifuit(bp);
Créez une fonction (méthode statique ou fonction hors classe) pele_mele
:
BrochetteGen<FruitAPeler>
qu'avec une BrochetteGen<Banane>
.Quel est le "meilleur" type statique du paramètre de la fonction ?
Peut-on vraiment l'invoquer avec une BrochetteGen<Fruit>
? Si non, pourquoi ?
// On veut pouvoir écrire un truc du genre:
BrochetteGen<FruitAPeler> bp = new BrochetteGen<FruitAPeler>();
// embrochage de fruits variés dans bp.
pele_mele(bp);
// On aimerai aussi pouvoir écrire un truc du genre:
BrochetteGen<Fruit> bf = new BrochetteGen<Fruit>();
// embrochage de fruits variés dans bf.
pele_mele(bf);
Créez une fonction (méthode statique ou fonction hors classe) appel_a_peau
:
BrochetteGen<FruitAPeler>
qu'avec une BrochetteGen<Fruit>
.Quel est le type meilleur statique du paramètre de la fonction?
Peut-on l'invoquer avec une BrochetteGen<Banane>
? Si non pourquoi?
// idéalement on veut pouvoir écrire un truc du genre:
BrochetteGen<FruitAPeler> bp = new BrochetteGen<FruitAPeler>();
appel_a_peau(bp); // des fruits variés ont été embrochés.
// et quelque chose du genre
BrochetteGen<Fruit> bf = new BrochetteGen<Fruit>();
appel_a_peau(bf); // des fruits variés ont été embrochés.
Comparez les solutions de ces langages par rapport à
Une archive .zip
ou .tar.gz
contenant:
nit/
nit/brochette.nit
Critères de qualité:
diff
)