Est-ce que c'est dans le contrat ?

 


    En théorie de l'informatique, on utilise ce que l'on appelle des paradigmes. Il existe plein de paradigmes différents actuellement. Les paradigmes consistent à volontairement limiter les possibilités offertes par le langage de programmation afin de rendre celui-ci plus intelligible et maintenable. Ainsi, lorsque l'on respecte le paradigme de la programmation structurée, on s'interdit d'utiliser l'instruction GOTO. Certains langages supportent nativement plusieurs paradigmes, par contre notre bon vieux BASIC du CPC ne facilite pas vraiment la tâche. En même temps, le CPC est sorti en 1984 !

    Ce n'est qu'en 1985 que Bertrand Meyer a présenté un nouveau paradigme : la programmation par contrat par le biais de son langage Eiffel. Pour simplifier, ce langage permettait au programmeur de rajouter des instructions dédiées permettant d'arrêter l'exécution si jamais une condition ou plusieurs conditions ne sont pas vérifiées. Il était bien sur possible de faire cela avec d'autres langages avec des instructions classiques, mais cela rajoutait du code qui semblait alors faire partie de l'algorithme implémenté alors que le langage Eiffel permettait de les écrire simplement avec une forme explicite. 

    Ce concept est très puissant et au demeurant très intuitif pour la plupart des programmeurs. Il y a une raison à cela, c'est qu'en fait, lorsque nous apprenons à programmer, nous découvrons les instructions d'un langage, leur logique, généralement dans des manuels. Les manuels détaillant ce que les instructions attendent en entrée, et ce qu'elles donnent en sortie. Il s'agit là, déjà d'une logique très similaire à celle d'un contrat ! Donnez une chaine de caractère à une instruction attendant un entier et vous verrez votre programme s'arrêter avec un message d'erreur.

    Mais il s'agit là d'un cas d'école, car le "contrat" décrit dans un manuel ne fait que quelques lignes et ne couvre pas forcément toutes les utilisations possibles ! Et donc si l'on trouve nulle part dans la documentation du langage, quel comportement est censé avoir le langage, que peut-on faire ?

    La première idée serait de simplement d'expérimenter, et prendre les résultats obtenus pour déduire le comportement que l'on peut attendre pour ces zones d'ombre de la documentation. Cela parait tout à fait logique, et beaucoup de personnes font cela pour tirer le meilleur parti de la technologie qu'ils emploient. Il faut aussi se rappeler que c'est une pratique qui était très courante à l'époque de l'Amstrad CPC car nous n'avions pas Google, CPCWiki, ACPC.Me etc...

    Cette méthode si bonne soit-elle, a tout de même des limites ! Les limites sont d'abord celles de notre jeu de tests. Si on emploie un jeu de tests trop limité, on peut passer à coté du réel fonctionnement de l'instruction et tirer des conclusions hâtives qui nous feront défaut quand le cas non testé arrivera enfin ! Une autre limite, c'est notre propre compréhension ! En effet, si l'on prend des résultats bruts d'une instruction, et que l'on cherche une logique à ses résultats, on peut facilement tirer une règle très complexe et qui parfois s'avèrera fausse pour d'autres cas que vous n'avez pas testé !

    Je me suis déjà trouvé dans ce cas de figure quand j'étais au lycée et que je n'avais donc accès à mon CPC que pendant  les WE et les vacances. J'avais essayé de comprendre le fonctionnement de l'instruction POKE au niveau de la mémoire vidéo. Je me limitais à l'époque au mode 0, et donc si j'avais bien noté qu'un POKE permettait d'afficher 2 pixels en même temps, la façon dont le deuxième paramètre permettait de fixer l'encre de ces 2 pixels restait un mystère que le manuel du CPC n'expliquait pas ! Qu'à cela ne tienne, j'ai patiemment fait des tests sur les 256 valeurs possibles et tenté d'en dégager une règle...Et bien, la règle que j'en ai déduite à l'époque était fausse ! J'étais passé totalement à coté de la logique de décalage d'un bit pour affecter le premier ou le second pixel !

    Vous allez me dire, mais quel est le rapport avec ton projet ? Et bien, je me retrouve une fois de plus dans cette situation ! J'ai beau avoir utilisé l'interpréteur BASIC pendant des années, il reste pour moi encore des zones d'ombre ! Avec l'ile au trésor, je me suis aperçu que cet interpréteur pouvait avoir un comportement très bizarre quand on approche des limites de la mémoire disponible. Au lieu de chercher précisément quand on atteint réellement cette limite, j'ai opté pour l'autre approche que beaucoup de programmeurs suivent dans le monde professionnel : Celle de rester dans les cas prévus par la documentation. Et donc, pour ce qui concerne l'occupation de la mémoire par le basic, je fais en sorte qu'elle soit aussi réduite que possible. Mon expérience m'a montré que le résultat de l'instruction fre(" ") n'était pas forcément à prendre au pied de la lettre. En effet, alors que cette dernière m'indiquait qu'il me restait environ 4000 octets de libre, l'interpréteur BASIC commençait déjà à écraser des variables en mémoire ! Parfois, le code était même corrompu ! Il s'agissait peut-être d'un problème de fragmentation de cette mémoire libre, mais en définitive je n'ai aucune explication fiable pour cela ! On touche là encore les limites de l'expérimentation donc !

    Pour limiter la place occupée par le listing basic, une des premières choses que l'on apprend c'est à se servir de l'instruction chain merge. Cette instruction d'après le manuel permet de charger un bout de programme basic au sein de son programme, tout en effaçant d'autres lignes et aussi de faire un GOTO à la ligne de notre choix. La description de cette instruction fait tout un paragraphe, et pourtant l'expérience montre qu'elle est très incomplète !

    Dans le jeu l'ile au trésor, j'ai découvert que la ligne indiquée en deuxième paramètre de cette instruction peut être stockée dans une variable ! C'est un fait unique dans notre interpréteur, les instructions GOTO et GOSUB et leurs dérivés On xxx ne le peuvent pas ! Ca ne figure pourtant pas dans le manuel ! J'ai aussi découvert que si l'on indique que si la ligne indiquée en deuxième paramètre n'existe pas préalablement dans le programme appelant, alors l'instruction déclenche une erreur. C'est à prendre en compte, si l'on pensait effectuer directement un saut dans le programme que l'on charge, il faudra que le programme appellant contienne cette ligne d'appel avec juste un REM qui sera écrasé par le chargement.

    Toujours dans l'optique de diminuer l'empreinte mémoire d'un programme, je me suis posé la question suivante : Est-ce que la ligne qui contient la déclaration d'un tableau doit être conservée si l'on veut conserver celui-ci en mémoire ? Après tout le basic a une instruction spécifique ERASE pour libérer la mémoire occupée par ceux-ci. J'ai donc réalisé les 2 programmes suivant pour faire une première expérimentation : 



    Là encore, rien n'est clairement dit là dessus dans le manuel ! Une ligne de code n'est qu'une ligne, ça ne devrait pas représenter grand chose, mais j'ai plusieurs tableaux qui vont rester en mémoire et être utilisés en permanence. Si je peux récupérer tout l'espace que les instructions DIM occupent, ça sera toujours ça de pris !

    Quand j'exécute le premier programme qui charge donc le second en écrasant ses lignes y compris celle contenant les DIM et en recommençant l'exécution à la ligne 10, j'obtiens le résultat suivant sur un CPC 464 : 


Et j'obtiens le résultat suivant sur un CPC 6128 : 


    Vous noterez que cela fait à 2 octets prêts, 4 kio de libre en plus sur le CPC 6128, alors qu'au démarrage une CPC 464 doté d'un lecteur de disquette dispose exactement de la même quantité de mémoire libre à savoir 42249 octets ! Donc à priori, l'exemple montre que même en forçant l'appel du ramasse miette avec FRE(" "), un tableau déclaré reste en mémoire même si la ligne contenant son DIM a disparue ! J'aurai aimé avoir une documentation plus complète de cette instruction finalement. Elle permet de faire plein de choses très intéressantes, mais on ne sait pas forcément jusqu'où vont les services de celle-ci ! Quelque part, s'engager dans ces zones inconnues, c'est un peu comme compter sur un contrat d'assurance dont on n'a pas lu les petites lignes et les renvois vers d'autres documents non fournis !

    Et vous, avez-vous plus de documentation sur le comportement de cette instruction et de l'interpréteur BASIC du CPC par rapport aux variables de type tableau ?
    



    



Commentaires

Posts les plus consultés de ce blog

Démarrage officiel du projet Felgon : Courage et vérité

Petite progression