Récit d’une expérience menée en Seconde durant l’année 2010-2011, sur la programmation objet.
L’article entre dans le cadre del’appel à contributions n° 2
La programmation objet est un paradigme, apparemment difficile à appréhender pour qui a déjà pratiqué la programmation impérative, et instinctive pour ceux qui « sont tombés dedans étant petits ».
C’est le cas de « jeunes » profs de maths, qui ont bien plus de choses à apporter à leurs aînés (pour peu que ceux-ci soient capables de les écouter), qu’on le soupçonnerait. Ainsi, à la fin de l’article Wikipedia sur les CaRScripts, je cite, juste en passant, la possibilité de faire de la programmation objet en JavaScript (alors qu’à l’époque, je n’avais pas la moindre idée de ce dont je parlais). Jérôme Caré, en lisant ceci, a construit un objet nombre complexe, qui illustre les principales notions de la programmation objet de manière géométrique (dans le plan d’Argand). Cet article m’a servi d’introduction à la programmation objet, moi qui ne suis pas « tombé dedans », et m’a donné envie d’expérimenter cela en classe de Seconde, pour les deux raisons suivantes :
- Il me semble qu’il est de ma responsabilité à moi, enseignant, de faire « tomber mes élèves dans la marmite » de potion magique (la marmite de la programmation objet en l’occurence) tant qu’ils sont encore « petits ».
- Les élèves entrant en Seconde ont traditionnellement de vieilles lacunes sur les fractions, et l’occasion était rêvée, de mettre leurs connaissances en action, parce qu’on apprend mieux lors d’un acte de création que par un simple apprentissage (mettre en action une notion lors de la création d’un algorithme, n’autorise pas l’élève à relâcher l’attention). Citons Piaget :
- « Apprendre, c’est créer ».
- « On ne connaît un objet qu’en agissant sur lui et en le transformant. »
J’ai donc décidé de mettre l’« accompagnement personnalisé » à profit pour animer, tout au long de l’année scolaire, un atelier sur la programmation objet. Voici ce que ça a donné :
propriétés
Un objet (dans le cas présent, une fraction) peut posséder
- des propriétés qui sont des variables (par exemple, des nombres)
- des méthodes qui sont des fonctions portant sur ces objets.
Pour commencer par le commencement, une séance a été faite sur les propriétés seules de l’objet fraction, les méthodes étant un sujet assez vaste pour être abordé plus tard...
Un pas vers l’abstrait a de suite été fait, en permettant de stocker une fonction JavaScript dans une variable. Normalement, les choses qu’on « met dans le tiroir » sont, en Seconde du moins, des nombres. Mais avec CaRMetal, les élèves découvrent vite que l’algorithmique peut aussi manipuler des objets géométriques, et l’usage de tableaux en algorithmique se répand même en Seconde (trier un tableau, c’est appliquer la fonction, ou méthode, tri, à l’objet tableau).
Puis la notation this (pour accéder en local aux variables passées à la fonction lors de son appel) a été introduite, et enfin les définitions
- Le numérateur d’une fraction est une propriété de celle-ci ;
- Le dénominateur d’une fraction est une propriété de celle-ci ;
- La valeur (approchée) d’une fraction est une propriété de celle-ci.
Le tout a été fait sous la forme d’un exercice vidéoprojeté, la feuille complétée au fur et à mesure par les élèves. La voici :
Cette activité est intéressante parce qu’elle permet
- de rappeler les notions de numérateur et de dénominateur, dans un contexte actif
- de rappeler qu’une fraction (mathématiques) est un nombre, ce que trop peu d’élèves de Seconde savent (pour eux, c’est une abstraction destinée à les embêter)
- d’habituer les élèves à la notation avec des points, à laquelle ils seront vite confrontés avec les Math.random() et autres tableau.sort() ;
- de présenter, assez discrètement, la notion d’instanciation, une fraction n’existant pour JavaScript, que lorsqu’on la crée !
Au cas où les élèves auraient été très rapides, des questions ont été ajoutées à la fin de l’exercice, sur l’objet point des logiciels de géométrie dynamique, et la recherche de quelques-unes de leurs propriétés (il y en a beaucoup !).
pgcd
Comme on a besoin de calculer un pgcd pour simplifier une fraction (à moins de combiner des boucles et des tests), il fallait une fonction pgcd avant de pouvoir commencer à travailler sur l’objet fraction (pour la méthode simplification, qui est fondamentale).
Ce travail a été fait sous la forme d’un devoir maison dont l’énoncé était simplement :
Écrire en JavaScript, l’algorithme d’Euclide.
Avec tout de même une ébauche pour rappeler la syntaxe :
- function pgcd(x,y){
- var d;
- return d;
- }
Et une notation introduite oralement : Le symbole « pourcent » donne, en JavaScript, le reste dans la division euclidienne, et se lit « modulo ».
Comme on pouvait s’y attendre, les meilleurs élèves ont cherché la réponse sur Internet, et parfois même ont utilisé, sans citer leur source, un document que j’avais créé il y a quelque temps !
Le meilleur devoir finalement a été celui d’un élève qui n’a pas pensé à créer une fonction pgcd mais a mis en place l’algorithme en ne s’aidant d’Internet que pour se renseigner sur la syntaxe de JavaScript. Il a commencé par remplacer a par b et b par a modulo b, séquentiellement (dans une boucle à condition d’arrêt). Il a constaté que le résultat affiché n’était pas le pgcd de a et b, et il a pensé à ajouter une variable c pour y stocker le reste euclidien provisoirement, et ne pas écraser d’autre variable ! Ce miracle s’explique peut-être par le fait qu’un TP analogue avait été fait au début de l’année...
Voici son devoir :
- a=Input("Entrez le plus grand nombre:");
- b=Input("Entrez le plus petit nombre:");
- while(b>0){
- var c=a%b;
- a=b;
- b=c;
- }
- Alert("Le PGCD des deux nombres est "+a);
Pour la qualité du travail et celle du résultat, le devoir de cet élève a donc été choisi pour le sujet suivant [2], en le transformant en fonction :
- function pgcd(a,b){
- while(b>0){
- var c=a%b;
- a=b;
- b=c;
- }
- return a;
- }
méthodes
Les activités des deux onglets précédents n’avaient qu’un seul but : Préparer celui-ci. L’objet était la découverte de méthodes de l’objet fraction, à savoir
- son affichage (qui ne renvoie rien)
- son inverse
- son opposé.
Mais avant tout, un exercice : Rajouter une nouvelle propriété, le signe de la fraction (propriété plus booléenne que numérique d’ailleurs).
Et cette remarque : Plutôt qu’avoir à faire
- Println(f.numérateur);
- Println(f.dénominateur);
pour avoir la valeur exacte d’une fraction f, il vaut mieux avoir à faire
- f.affichage();
une fois pour toutes (et en plus, on peut envisager par la suite d’améliorer la méthode d’affichage sans avoir à tout refaire ; en effet, la gestion du signe, de la simplification automatique et du trait de fraction horizontal ont été laissés à plus tard).
La première méthode de l’objet fraction a donc été son affichage.
Voici l’énoncé du devoir maison :
Quelques perles relevées dans les devoirs :
- Pour le test sur le signe de la fraction [3], plusieurs élèves ont rédigé, au lieu du
n*d>=0
, un"n multiplié par d est égal ou supérieur à 0"
. Il est possible qu’ils se soient fait dicter la solution au téléphone... Il est d’ailleurs remarquable que le signe du produit ait été quasiment aussi populaire que celui du quotient lui-même, ce qui montre à quel point une fraction peut être un objet abstrait pour des élèves de Seconde ! - L’algorithme consistant à diviser les numérateur et dénominateur d’une fraction par leur pgcd pour rendre celle-ci irréductible est assez peu connu des élèves de Seconde : 3 élèves sur 30 l’ont fait. Dont un qui a essayé un
new pgcd
qui montre que le pgcd est pour lui un objet au même titre que la fraction, et un qui a transformé l’algorithme d’Euclide en méthode de l’objet fraction (voir plus bas). - Seuls 6 élèves sur 30 semblent savoir ce qu’est l’inverse d’une fraction, dont un qui n’a pas réussi à échanger les deux valeurs, oubliant le TP portant là-dessus !
- L’opposé, bien que long à calculer, a eu plus de succès, visiblement les élèves se sont pris au jeu, en essayant de choisir entre $\frac{-n}{d}$ et $\frac{n}{-d}$ celle qui leur paraissait le mieux. Cependant, ils ont séparé en 4 cas (numérateur positif ou négatif et dénominateur positif ou négatif) alors que seul le signe du dénominateur importe. L’un d’eux a essayé de remplacer le « + » de la concaténation par un « - » dans
Println(n-"/"+d);
. De façon générale, la distinction entre un affichage et un retour est assez floue. Et un algorithme est considéré comme correct s’il passe victorieusement quelques tests, ce qui montre l’importance de la démarche expérimentale en algorithmique...
Quelques copies :
Un seul élève (la meilleure copie) a trouvé une méthode additionnelle : l’affichage décimal (qui existait déjà en tant que propriété sous le nom valeur). Pourtant, on venait de voir la fonction carré qui, comme toute fonction numérique, est une méthode de l’objet fraction. Mais combien d’élèves de Seconde se rappellent que $\left(\frac{n}{d} \right)^2=\frac{n^2}{d^2}$ ?
Affichage
Une méthode intéressante pour l’objet fraction est son affichage. L’algorithme est intéressant parce que pour calculer la longueur du trait de fraction, on utilise une boucle (compter le nombre de chiffres du numérateur par exemple). L’idée est d’imprimer entre la ligne du numérateur et celle du dénominateur, une suite de signes « - » évoquant le trait de fraction :
- this.affichage=function(){
- l=Math.max(n.toString().length,d.toString().length);
- Println(n);
- Print("");
- for (i=0;i<=l;i++){Print("-");}
- Println("");
- Println(d);
- Println("");
- }
Mais outre le fait que le résultat n’est pas si terrible, les élèves ont commencé à ce stade à faire un blocage sur la programmation objet, ce qui m’a mené à renoncer à aller plus loin...
On peut faire encore mieux pour l’affichage de la fraction :
- this.affichage=function(){
- Text("$\\frac{"+n+"}{"+d+"}$",-3,2);
- }
Pour voir des exemples d’affichages élaborés de fractions dynamiques, on peut essayer le dossier CaRMetal en bas de cet article sur l’algorithme de Stern-Brocot.
Opérations
Les méthodes d’un objet (comme les fractions) sont typiquement des fonctions (obtention d’une fraction ou d’autre chose à partir d’une fraction). Mais comment implémenter une opération, qui fait intervenir une autre fraction ? En fait c’est plus facile que ça en a l’air, puisqu’il suffit de mettre l’autre fraction dans les fameuses parenthèses vides :
En fait il y a là quelque chose d’assez subtil, qui s’apparente à un fossé entre l’algèbre et l’algorithmique, voire entre le prof et ses élèves : La notation des opérations est infixée, donc
- On ne parle plus de somme de deux fractions, mais d’une fraction additionnée avec une autre (nécessaire pour considérer la somme comme une propriété de l’objet)
- On ne parle plus de différence entre deux fractions, mais de fraction soustraite à une autre (plus précisément, de fraction à laquelle on soustrait une autre)
- On ne parle plus de produit de fractions, mais d’une fraction que l’on va multiplier par une autre ; autrement dit, puisque cette méthode est représentée en JavaScript par une function, la fonction est linéaire.
- On ne parle plus de quotient de fractions, mais de diviser une fraction par une autre, et la phrase du cours « diviser par une fraction, c’est multiplier par son inverse » prend tout son sens ici.
Cette manière d’infixer les opérations, fondamentale en programmation objet puisqu’elle date de Smalltalk, permet aussi (grâce à la surcharge des opérations) de parler de la somme d’une fraction avec autre chose qu’une fraction (géré dans Python 2.7) mais modifie aussi considérablement le vocabulaire de la géométrie :
- Plutôt que de parler du milieu d’un segment ou d’une paire de points, on parle du milieu d’un point avec un autre, qui s’obtient sous DrGeoII en s’arrêtant à mi-chemin dans le parcours allant du premier point au second ;
- Plutôt que de parler de la parallèle à une droite par un point, on évoque le transport parallèle de la droite jusqu’à ce qu’on arrive au point !
- Plutôt que de parler d’un vecteur d’origine et d’extrémité données, on parle du vecteur allant d’un point à un autre.
- Même les cercles sont décrits différemment, avec l’idée de on part du centre, on règle l’écartement du compas jusqu’à un point, on trace le cercle qui est plus procédural que descriptif.
Et que dire du pgcd, qui, infixé (on parle alors du pgcd avec b), éviterait peut-être qu’un élève de Seconde, à qui on demande de calculer le pgcd de 24 et 32, remplisse une page de calculs pour calculer le pgcd de 24, la seconde page étant bien entendu réservée au calcul du pgcd de 32 [4] ?
L’implémentation en CaRScript des propriétés et méthodes de l’objet complexe a été décrite ici.
Pistes
Puisque l’expérience n’est pas franchement une réussite, peut-être vaudrait-il mieux la mener dans d’autres circonstances :
- L’utilisation d’un langage plus concis que JavaScript pourrait éventuellement faciliter la tâche. On peut penser à Python et Ruby ou au tout nouveau BYOB...
- Le sujet des fractions est peut-être trop abstrait, on peut lui préférer quelque chose de plus graphique, comme la géométrie repérée ; ce qui permet de faire le cours assez vite, de façon active, et de faire découvrir par les élèves comment fonctionnent les logiciels de géométrie (ils [5] sont programmés comme des objets...)
- Mener ce genre d’activité sous forme de DM, ce n’est pas très approprié ; le sujet se prête nettement mieux à un enseignement par projet. Les réalisations des élèves peuvent être « concurrentes » avec des outils différents ou des langages différents...