Choses lues dans le tout premier manuel de FORTRAN

Fortran Programmer’s Reference Manuel for the IBM 704, 1956.

FORTRAN a maintenant 54 ans. Ce qui est exceptionnel pour un langage dont Dijkstra(*) disait déjà, en 1975 :

FORTRAN – the infantile disorder – by now nearly 20 years old, is hoplessly inadequate for whatever computer application you have in mind today; it is now too clumsy, too risky, and too expensive to use.

Mais s’il était déjà vieux à vingt ans, le nombre d’applications écrites en FORTRAN depuis est considérable. Au point où dix pages d’offres d’emploi lui sont réservées sur www.job-search-engine.com.

Pour un vieux de la vieille comme moi (j’ai été élevé au VIC-20), FORTRAN a toujours possédé un certain attrait. Je ne l’ai jamais pratiqué, mais déjà, quand je brûlais ma jeunesse contre le clavier de mon premier 8088 (un ordinateur enfin sérieux !), rien ne me séduisait comme les petites annonces placées en fin de revue annonçant un compilateur FORTRAN professionnel livré sous trois jours et en autant de disquettes… C’était toujours cher, très cher, si cher en fait que ça me paraissait infiniment sérieux - enfin du vrai code ! Je ne comprenais pas tous les mots de ces annonces, ce qui leur donnait sans doute une certaine aura.

Le temps passa (que fait-il d’autre ?), je pratiquai avec plus ou moins de succès BASICA, l’assembleur 80286, l’assembleur 68000, Pascal, Modula-2, ADA, LISP, Prolog, C, C++, VB, C#, sans compter tout un tas d’autres petits dialects qu’on ne côtoie qu’un moment. Mais je n’eus jamais l’occasion de toucher ce vénérable langage. Et je n’y toucherai jamais, sauf par curiosité, un soir, chez-moi.

C’est ce que je m’apprêtais d’ailleurs à faire ce soir lorsque je tombai sur l’un des tout premiers manuels de FORTRAN. Édité en 1956 par IBM (qui d’autre), sa lecture me parut suffisamment intéressante pour en partager quelques passages. Les voici, mes commentaires en prime :

  • Object programs produced by FORTRAN will be nearly as efficient as those written by good programers [NDLR : en assembleur 704].

Il s’agit-là de la première qualité de FORTRAN (enfin, du compilateur correspondant) selon l’auteur. Et pour cause : avec des machines infiniment poussives (voisines d’une calculatrice moderne !), l’efficacité du code était d’une telle importance qu’elle en devenait obsessionnelle. Un langage n’aurait jamais pu s’implanter sans offrir une efficacité toute proche de l’assembleur. Voilà pourquoi le jeu d’instructions de FORTRAN est si près de l’assembleur. En particulier, toutes les variantes du GOTO ont été prévues.

  • The FORTRAN language is intended to be capable of expressing any problem of numerical computation. In particular, it deals easily with problems containing large sets of fomulae and many variables (…).

Je crois que FORTRAN fut sans rival en ce domaine jusqu’à l’arrivée, peut-être, de Fortress, en 2008 (d’autres langages servirent aux mêmes fins, dont C++, mais aucun n’en fit une spécialité tout en obtenant une belle popularité). Fortress est un FORTRAN revu au goût du jour développé par Sun Microsystem (également auteur de JAVA et maintenant passé dans le girond d’Oracle) .

  • However, for problems in which machine words have a logical rather than a numerical meaning it is less satisfactory, and it may fail entirely to express some such problems.

Fort intéressant : l’auteur signale d’emblée que FORTRAN n’est pas fait pour résoudre des problèmes qui ne sont pas mathématiques. Qu’on n’ait pas toujours tenu compte de son avis pourrait expliquer pourquoi FORTRAN a pu avoir un mauvaise réputation par moment. Vous connaissez l’adage : quand vous tenez un marteau, tout se met à soudainement à ressembler à un clou autour de vous…

  • Each statement is punched on a separate card.

Une ligne de code = une carte ! On comprend que la concision ait été une préoccupation majeure à l’époque. L’habitude a perdurée un moment – on rencontrait encore des : while ( *ptr1++ ); en C il y a encore quelques années…

  • If a statement is too long to fit on a single line of the coding form, the programmer can signal to the keypuncher that he has continued on to the next line by placing a mark in the column labeled CONTINUATION.

A retenir : il existait alors un métier, keypuncher, qui consistait à créer les cartes perforées correspondant au code écrit par un développeur… Chaque développeur avait donc son ou sa secrétaire – belle époque, surtout si elle était blonde :).

  • The order of the statements is governed solely by the order of the cards. However, any number (…) may be associated with any statement by punching it in column 1-5 (…). Thereupon this number becomes the statement number of that statement.

Autrement dit, on pouvait produire 4319 cartes séquentielles dont les instructions étaient exécutées précisément dans cet ordre, puis ajouter une carte portant le numéro 381.

  • Blank characters (…) are simply ignored by FORTRAN, and the programmer may use blanks freely to improve the readability of his FORTRAN listing.

Étant donnés les commentaires que je lis encore aujourd’hui (lorsqu’il y en a, c’est le plus souvent sans aucun formatage - tout est mis bout à bout, histoire d’être aussi peu invitant que possible et aussi peu maintenable que possible), je salue cette intention bien bas ! Mes coreligionnaires semblent insister pour ignorer le plus bel outil du développeur : le commentaire concis bien formatés. Pour donner une idée, toutes les best practices et tous les design patterns du monde n’arriveront jamais à la cheville d’un commentaire pertinent. Mais bon, c’est plus classe (et moins forçant) de montrer ce qu’on SAIT faire que d’expliquer ce qu’on VEUT faire. À mon avis, l’absence de commentaire précis mais concis explique encore que toute application coûte une fortune à maintenir (le coût de la maintenance étant généralement plus élevé que le coût du développement, ne l’oublions pas) – mais ce sera l’objet d’un prochain post :)

  • Variables : 1 to 6 alphabetic or numeric characters.

Yep, que 6 caractères pour indiquer : somme de Kronecker des matrices obtenues par calcul… Levons-leur notre chapeau, ça n’a pas dû être simple… A comparer avec : SommesPrimesGrandsChantiersNominaux = MontantTotalPrimesIncidentesParitairesNonTaxees * ( 1 + TauxExtraordinairesAnnulalise). À l’époque, c’était sans doute : SPGCN = MTPPNT * ( 1 + TEA)

  • Fixed point variables are distinguished by the fact that their first character is I, J, K, L, M, N.

Ces lettres correspondent aux indices de matrice les plus fréquents en mathématiques. C’était probablement sans surprise la plupart du temps. Par contre, MOONDIST (distance Terre-Lune) était un entier par définition, ce qui a pu poser certains problèmes. Et expliquer certains crashes ! 

  • A 2-dimensional array A will, in the object program, be stored sequentially in the order A1,1, A2,1, … Am,1, A1,2, A2,2, … Am,2, … Am,n. (…) All arrays is stored backward in storage.

Tout l’inverse de nos compilateurs modernes qui font du nième indice celui qui varie le plus. J’ai beau chercher pourquoi nous n’avons pas conservé cette représentation en mémoire, je ne trouve pas. J’en conclus que cet ordre était dicté par le jeu d’instructions du 704 (je n’ai pas trouvé de manuel concernant la programmation du 704, si quelqu’un a des liens…).

  • The name of the function is 4 to 7 alphabetic or numeric characters (…) of which the last must be F and the first must be alphabetic. Also, the first must be X if and only if the value of the function is to be fixed point.

Hello again, ma belle hongroise :) Ainsi, le nom d’une fonction se termine toujours par F et commence par X si le résultat est un nombre réel présentant un nombre fixe de décimales. Bon, la notation hongroise, la vraie, n’a qu’un lointain rapport, mais celle qu’on appliqua longtemps sous Windows me semble directement liée. Une exellente idée sans doute à l’époque, une très mauvaise idée par la suite. Tiens, ça me rappelle qu’un collègue appliquait encore ce suffixe ‘F’ à toutes les fonctions C qu’il écrivait. C’était en 2002, 2003… Ajoutons à ce travers déplaisant qu’il affectionnait vi (alors que tout les développeurs utilisaient UltraEdit). J’en conclus maintenant qu’il avait fait pas mal de FORTRAN :) 

  • Beside the built-in routines, any single-valued function of any number of arguments can be made available to the programmer by placing the appriopriate routine on the master FORTRAN tape.

Quelle époque ! Hey, Gus, tu me montes la bobine 39 ? J’ai besoin de XABS.­… Dire que certains en veulent encore à Visual Basic !

  • If E and F are expressions, and F is not floating point unless E is too, and the first character of D is not + or , and neither E nor F is of the form A**B, then E ** F is an expression of the same mode as E. Thus A**(B**C) is an expression, but I**(B**C) and A**B**C are not.

Essayez seulement de comprendre ce que l’auteur voulait insinuer et je vous poste ma paie de ce mois-ci ! Voilà une superbe illustration du mot abscon…

  • The = sign in an arithmetic formula has the meaning “is to be replace by”.

Nous n’y pensons plus, mais écrire x=3 pour assigner la valeur 3 à x n’a rien à voir avec les maths que nous avons apprises : en math, l’opérateur = est un comparateur et ne change surtout pas la valeur de x ! Cela dit, certains langages utilisaient des graphies plus mathématiquement correctes, comme x <= 3.

  • Chapter 4. The FORTRAN language : Control Statements. Unconditional GO TO, Assigner GO TO.

Il peut sembler hérétique que les premiers mots clés de FORTRAN listés dans ce manuel soient les différentes saveurs de GOTO, mais sachant qu’il faut comparer FORTRAN non pas aux langages qui l’ont suivi mais à ceux qui l’ont précédé, c’était sans doute la moindre des choses. FORTRAN succédait à l’assembleur et quiconque à fait de l’assembleur peut comprendre.

  • ASSIGN i TO N.

Par exemple : ASSIGN 100 TO N. Cette instruction permet d’assigner un label à un variable. Ainsi, ASSIGN 100 TO N permettra de brancher au label 100 en écrivant GO TO N. Mine de rien, il s’agit-là de l’un des ancêtres du polymorphisme (les langages objet n’ont pas inventé grand chose, si ce n’est certains mécanismes simplifiés d’encapsulations et tout un tas d’outils pour rendre le code un peu moins maintenable, hélas ! Mais ce sera l’objet d’un prochain post :). 

  • Computed GO TO : GO TO (n1, n2, …, nm) i.

Ceci permet de brancher à nj selon la valeur de i. Ainsi, GO TO (100, 200) i branchera à 200 si i vaut 2. Si i vaut 3, par contre, le manuel ne prévoit rien… Le GOSUB ON de BASIC a donc un ancêtre…

  • IF : IF (a) n1, n2, n3.

Permet de brancher à n1, n2 ou n3 selon que a est négatif, nul ou positif. Tiens tiens tiens… Ça ne vous rappelle pas strcmp ? Je me suis longtemps demandé comment on avait pu définir quelque chose d’aussi peu lisible que strcmp – maintenant je sais :)

  • SENSE LIGHT, IF (SENSE LIGHT), IF (SENS SWITCH).

Le premier allume ou éteint certaines diodes situées sur la console de l’opérateur, les suivants permettent de brancher si les diodes sont allumées ou pas… Comme low level, on a rarement vu mieux :)

  • IF ACCUMULATOR OVERFLOW n, m. IF QUOTIENT OVERFLOW n1, n2. IF DIVIDE CHECK n1, n2.

Permet de brancher sur n ou sur m en fonction du statut de l’accumulateur. Nous utilisons maintenant des exceptions. Progrès ? Pas toujours : au lieu de voir la diodes 3 clignoter, nous obtenons généralement un message sibyllin : “Une exception a été levée, veuillez contacter le service informatique.” Lequel service, bien entendu, n’a aucun idée de ce qui a pu se passer puisque les traces ne cite que ce message… Morale ? Toute simple : Toujours tracer les exceptions systèmes là où elles se produisent, quitte à les tracer à nouveau au plus haut niveau (mieux vaut deux fois qu’une ou qu’aucune). Et ne jamais, jamais, jamais remplacer une exception système par une exception maison (ex : remplacer DivideByZeroException par ModuleComptaGeneralException). Luxe : dans la méthode où l’exception se produit, profiter du catch pour tracer les paramètres reçus par cette exception. Oui, c’est lourd, mais oui, ça coûte finalement moins cher en maintenance pour nos clients qui ont d’autres chats à fouetter :) 

  • DO n i = m1, m2[, m3].

Correspond à nos modernes FOR n = m1 TO m2 STEP m3, ou, plus fréquemment : for (n = m1, n <= m2, n += m3). La syntaxe est au moins curieuse : DO 100 i = 1, 10, 2 pour FOR i = 1 TO 10 STEP 2 : PRINT “HELLO, WORLD”.

  • Transfer on Control and DOs. Transfers of control by IF-type or GO TO-type statements are subject to the following rule : No transfer is permitted into the range of any DO from outside its range.

En d’autres mots, il n’est pas possible de sauter dans une boucle ni de sortir d’une boucle inscrite pour sauter dans la boucle conscrite. Ça me semble une assez bonne idée… Il existait cependant une exception, assez périlleuse il me semble : on pouvait brancher depuis l’intérieur d’un DO vers une routine quelconque et revenir par un GOTO…Autre lame à fort double-tranchant : les indices de boucle (les i, j, k, l, m…) conservaient leur valeur lorsqu’on sortait sauvagement d’une boucle, ce qui permettait de la réintégrer par la suite. Une sortie normale en revanche invalidait ces indices, et le tout devait prêter à confusion. Chose bien vue toutefois : il n’était pas possible de modifier l’indice d’une boucle à l’intérieur de celle-ci – elle était immutable. Certains de nos langages modernes auraient dû en prendre de la graine (C, C++)…

  • Four more statements (READ TAPE, READ DRUM, WRITE TAPE, and WRITE DRUM) call for ordinary binary tranmissions of a list of quantities.

Superbe pour quiconque s’intéresse à l’âge de pierre de l’informatique ! Mais encore heureux que les disquettes, CD-R/W, clés USB, espaces disque in the cloud et autres disques externes n’aient pas existés à l’époque – la liste des mots clés eut été autrement plus longue ! 

  • FORMAT (I2 / (E12.4, F10.4)).

Le formatage des nombres a toujours été fort complexe, et pour cause : nous voulons tout et n’importe quoi. Ce l’est donc toujours en C#, mais quand même un peu moins… Chose intéressante, il était prévu plusieurs formatages permettant de rendre des nombres “compatibles” aux machines Hollerith. (Hollerith fut un précurseur dans nombre de domaines touchant l’informatique).

  • The READ statement causes the object program to read cards from the attached card reader.

Les bases de données ont définitivement évolué… Imaginez un moment le nombre de pas dans la salle des serveurs qu’engendrait un pauvre SELECT 

  • The FREQUENCY statement permits the programmers to give his estimate, for each branch-point of control, of the frequencies with wiche the several branches will actually be executed in the object program. This information is used to optimise the use of index registers in the object program.

Voici un énoncé qui semble incroyable à première vue, mais ce n’est jamais que l’équivalent du mot clé register de C…

  • One important type of optimisation, concerned with common subexpressions, takes places only if the expression has been suitably written.

Dans l’expression suivante : Y = (A * B) * C + SINF(A * B), la mise entre parenthèses de (A * B) est une optimisation puisque FORTRAN ne calculera qu’une seule fois A * B. Bien pensé.

(*) Dijkstra : vous aviez remarqué ? Dijkstra est le seul nom que je connaisse à aligner trois indices de boucle ! C’était prédestiné…

Ajouter un commentaire

Les retours à la ligne suivantes sont automatiques.
Codes XHTML permis : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>