Les nouvelles technologies pour l’enseignement des mathématiques
Intégration des TICE dans l’enseignement des mathématiques

MathémaTICE, première revue en ligne destinée à promouvoir les TICE à travers l’enseignement des mathématiques.

Découverte de la programmation objet en JavaScript : Le cas des fractions

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

Article mis en ligne le 7 juin 2011
dernière modification le 25 avril 2021

par Alain Busser

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 :

  1. 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 ».
  2. 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 :
  1. « Apprendre, c’est créer ».
  2. « 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 :

propriétés de l’objet fraction

Cette activité est intéressante parce qu’elle permet

  1. de rappeler les notions de numérateur et de dénominateur, dans un contexte actif
  2. 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)
  3. d’habituer les élèves à la notation avec des points, à laquelle ils seront vite confrontés avec les Math.random() et autres tableau.sort() ;
  4. 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 :

  1. function pgcd(x,y){
  2.     var d;
  3.  
  4.  
  5.     return d;
  6. }

Télécharger

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 !

Voici quelques copies :

copie 1

Cette élève [1] n’a pas écouté les explications sur la syntaxe de l’opération « modulo » et a recréé l’algorithme de division euclidienne pour les besoins de cet exercice. Comme le suggère la reproduction calligraphique de la coloration syntaxique de CaRMetal, le programme est correct pour la partie pgcd. Par contre, la partie division euclidienne affiche un message d’erreur à cause d’une confusion entre la valeur de retour d’une fonction et les tableaux.


copie 2

Cet élève a utilisé l’algorithme des soustractions, qui est correct mais l’affichage est fait en html et ne fonctionne donc pas dans CaRMetal. D’ailleurs tel qu’il est, il ne fonctionne pas non plus en html parce qu’il est incomplet.


copie 3

Cette élève utilise aussi les soustractions successives, et la partie test ne fonctionne pas non plus dans CaRMetal parce que dans ce dernier, l’entrée se fait par Input et pas par prompt.


copie 4

En fait il y a deux erreurs de syntaxe :

  • Une accolade fermante manque ;
  • Il n’y a pas de return et la fonction ne renvoie rien.

copie 5

Cet algorithme fonctionne correctement, mais n’a pas été choisi pour la suite, parce que l’affectation du reste est faite en même temps que le test, ce qui rend le script peu compréhensible par les autres élèves.

Corrigé du devoir

Beaucoup d’élèves ont pratiquement rendu feuille blanche, ce qui a nécessité le rappel de quelques principes :

1 : L’utilisation du papier-crayon : Il a fallu demander aux élèves de rappeler, oralement, comment fonctionne l’algorithme d’Euclide, au tableau. Un exercice a alors été mené collectivement, sous la forme du calcul du pgcd de 53 et 27. Les élèves ont alors collectivement construit le tableau suivant, en citant de mémoire la nécessité d’y mettre 3 colonnes :

xyreste
53 27 26
27 26 1
26 1 0

À partir de là, la traduction en JavaScript a été presque immédiate. Pour vérifier, le mode pas-à-pas du tableur Open Office a été utilisé, avec l’affichage des variables x, y et r :

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 :

  1. a=Input("Entrez le plus grand nombre:");
  2. b=Input("Entrez le plus petit nombre:");
  3. while(b>0){
  4.         var c=a%b;
  5.         a=b;
  6.         b=c;
  7. }
  8. Alert("Le PGCD des deux nombres est "+a);

Télécharger

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 :

  1. function pgcd(a,b){
  2. while(b>0){
  3.         var c=a%b;
  4.         a=b;
  5.         b=c;
  6. }
  7. return a;
  8. }

Télécharger

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

  1. Println(f.numérateur);
  2. Println(f.dénominateur);

Télécharger

pour avoir la valeur exacte d’une fraction f, il vaut mieux avoir à faire

  1. 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 :

DM sur les méthodes

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 :

Copie 1

  1. fraction=function(n,d){
  2.         this.numer=n;
  3.         this.denom=d;
  4.         this.valeur=n/d;
  5.         if("n multiplié par d est égal ou supérieur à 0"){
  6.                 this.signe="+";
  7.         } else {
  8.                 this.signe="-";
  9.         }
  10.         this.affichage=function(){
  11.                 return (n+"/"+d);
  12.         }
  13.         this.simplifie=function(){
  14.                 var pgcdn=new pgcd(n,d);
  15.                 return new fraction(n/pgcdn,d/pgcdn);
  16.         }
  17.         this.oppose=function(){
  18.                 if("n supérieur à 0 & d supérieur à 0"){
  19.                         return new fraction(-n,d);
  20.                 }
  21.                 else {
  22.                         if("n inférieur à 0 & d inférieur à 0"){
  23.                                 return new fraction(n,-d);
  24.                         }
  25.                 } else {
  26.                         if("n inférieur à 0 & d supérieur à 0"){
  27.                                 return new fraction(-n,d);
  28.                         } else {
  29.                                 if("n supérieur à 0 & d inférieur à 0"){
  30.                                         return new fraction(n,-d);
  31.                                 }
  32.                         }
  33.                 }
  34.         }
  35. }

Télécharger

Cet élève est d’ordinaire un des plus en difficulté dans la classe !

meilleure copie : signe

  1. fraction=function(n,d){
  2.         this.numer=n;
  3.         this.denom=d;
  4.         this.valeur=n/d;
  5.         if(this.valeur>=0){
  6.                 this.signe="+";
  7.         } else {
  8.                 this.signe="-";
  9.         }
  10. }

Télécharger

Simplification tout objet :

  1. fraction=function(n,d){
  2.         this.numer=n;
  3.         this.denom=d;
  4.         this.affichage=function(){
  5.                 Println(n+"/"+d);
  6.         }
  7.         this.simplifie=function(){
  8.                 function pgcd(n,d){
  9.                         a=n;
  10.                         b=d;
  11.                         while(b>0){
  12.                                 var c=a%b;
  13.                                 a=b;
  14.                                 b=c;
  15.                         }
  16.                         return a}
  17.                 function simply(n,d){
  18.                         var e=n/a;
  19.                         var g=d/a;
  20.                 }
  21.                 return new fraction(e,g);
  22.         }
  23. }

Télécharger

Bien entendu, il y avait beaucoup plus simple, par exemple return new fraction(n/a,d/a); !

Meilleure copie : opposé

  1. fraction=function(n,d){
  2.         this.numer=n;
  3.         this.denom=d;
  4.         this.valeur=n/d;
  5.         if(n/d>0){
  6.                 if(n>0){
  7.                         Println(-n+"/"+d);
  8.                 } else {
  9.                         Println(n+"/"+-d);
  10.                 }
  11.         } else {
  12.                 if(n>0){
  13.                         Println(n+"/"+-d);
  14.                 } else {
  15.                         Println(-n+"/"+d);
  16.                 }
  17.         }
  18. }

Télécharger

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}$ ?

Production en ligne

Voici, toujours en JavaScript mais inclus dans du code html, une compilation des méthodes de plusieurs élèves de la classe (il a fallu corriger quelques erreurs) :

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 :

  1.         this.affichage=function(){
  2.                 l=Math.max(n.toString().length,d.toString().length);
  3.                 Println(n);
  4.                 Print("");
  5.                 for (i=0;i<=l;i++){Print("-");}
  6.                 Println("");
  7.                 Println(d);
  8.                 Println("");
  9.         }

Télécharger

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 :

  1.         this.affichage=function(){
  2.         Text("$\\frac{"+n+"}{"+d+"}$",-3,2);
  3.         }

Télécharger

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 :

La recette en JavaScript

  1.         this.plus=function(g){
  2.                 return new fraction(this.numer*g.denom+this.denom*g.numer,this.denom*g.denom);
  3.         }
  4.         this.moins=function(g){
  5.                 return this.plus(g.oppose());
  6.         }
  7.         this.fois=function(g){
  8.                 return new fraction(this.numer*g.numer,this.denom*g.denom);
  9.         }
  10.         this.sur=function(g){
  11.                 return this.fois(g.inverse());
  12.         }

Télécharger

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

  1. 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)
  2. 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)
  3. 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.
  4. 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 :

  1. 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...
  2. 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...)
  3. 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...