Histoire des langages de programmation -...

41
Histoire des langages de programmation Juin – Août 2006 http://www.aqualonne.fr.st Traduit de « Concepts of Programming Languages », Robert W. Sebesta

Transcript of Histoire des langages de programmation -...

Page 1: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation

Juin – Août 2006

http://www.aqualonne.fr.st

Traduit de « Concepts of Programming Languages », Robert W. Sebesta

Page 2: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 2

Table des Matières

Avant-propos 3 Annexe : Graphique d’évolution des principaux langages 4 Chapitre 1 : Questions fondamentales 8 Des langages pour quelles applications ?. . . . . . . . . . . . . . . . . 8 D’où vient la puissance d’un langage ?. . . . . . . . . . . . . . . . . . 10 Quelles peuvent être les influences sur la conception ?. . . . . . . . . . 14 Quelques débats : influence de la langue sur la pensée, langage unique. . 15 Qu’est-ce que la compilation ?. . . . . . . . . . . . . . . . . . . . . . 16 Comment s’exécute le code ?. . . . . . . . . . . . . . . . . . . . . . . 17 Quelles sont les autres manières d’exécuter un code ?. . . . . . . . . . . 18 Chapitre 2 : L’évolution vue par les langages majeurs 19 Le Plankalkül de Konrad Zuse. . . . . . . . . . . . . . . . . . . . . . . 19 Programmation machine minimaliste : Shortcode, Speedcoding, A-0. . . 20 L’IBM 704 et Fortran. . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 La programmation fonctionnelle : IPL, FLPL, LISP, ML, Miranda. . . . 24 Une première étape vers la maturité : ALGOL 60. . . . . . . . . . . . . 26 Le Business et l’informatique : COBOL. . . . . . . . . . . . . . . . . . 28 La simplicité : BASIC. . . . . . . . . . . . . . . . . . . . . . . . . . . 30 Tout pour tout le monde : PL/I. . . . . . . . . . . . . . . . . . . . . . . 31 Deux langages dynamiques : APL et SNOBOL. . . . . . . . . . . . . . 32 Vers une abstraction des données : SIMULA 67. . . . . . . . . . . . . . 32 ALGOL 68 et ses descendants Pascal, C, Modula-2, Oberon, Delphi. . . 33 La programmation logique : PROLOG. . . . . . . . . . . . . . . . . . . 36 Le plus grand effort de conception de l’histoire : Ada. . . . . . . . . . . 37 La programmation orientée objet : Smalltalk. . . . . . . . . . . . . . . . 39 Une combinaison d’impératif et d’orienté objet : C++ et Eiffel. . . . . . 41

Page 3: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 3

Avant-Propos Considérations sur l’approche adoptée « Ce livre est le fruit d’une façon d’enseigner les langages de programmation en intégrant les ‘deux approches’ qui interviennent dans la pédagogie. La première approche est basée sur les interpréteurs, tandis que l’autre se concentre sur un panorama des langages. […] La méthode de l’interpréteur écrit des programmes pour apprendre des concepts ; on considère qu’en apprenant à l’ordinateur comment exécuter un concept, nous apprenons à le comprendre nous-même. Même si ce raisonnement est intellectuellement cohérent, il reste un problème : comprendre les définitions n’implique pas que nous en comprenons bien les conséquences. Par exemple, la différence entre les ordres d’évaluation [c.f. Scheme p57], ou entre la gestion des environnements, se résume en quelques lignes du code pour l’interpréteur mais la conséquence de ces choix est énorme. Un tour d’horizon des paradigmes de programmation est donc conseillé pour bien comprendre les conséquences. »

Programming Languages : Application and Interpretation, Shriram Krishnamurthi Un historique « Au début du monde de l’informatique, on programmait en langage machine, c’est-à-dire directement en écrivant des suites de chiffres héxadécimaux. Très rapidement, on a donné des mnémoniques : des informations symboliques. Par exemple, MOV R0 R1 remplace 04 43 ; le langage d’assemblage était né (appelé aussi assembleur par abus). Ces instructions étaient très facilement traduites en langage machine (simple consultation des mnémoniques) par un programme : l’assembleur. On a ensuite rajouté des étiquettes : les BRANCH -32 ont peu devenir des BRANCH ‘boucle’ par exemple. Puis on a rajouté la possibilité d’exprimer directement des places mémoires en leur donnant un nom symbolique, au lieu de manipuler l’adresse en héxadécimal : la notion de variables était née. Dans les années 50, grand changement : on veut s’affranchir complètement de la machine en élaborant des langages de haut niveau. Sont alors introduits des concepts qui n’existent absolument pas dans le langage machine : expressions arithmétiques, variables locales, fonctions avec paramètres, structures de données… Il devient nécessaire de concevoir des programmes qui traduisent les énoncés en instructions directement exécutables par une machine : des compilateurs. »

Compilation : Théorie des langages, Université de Bretagne Occidentale

Pourquoi s’intéresser à cette théorie « Cela apporte de nouvelles connaissances pour choisir le bon langage dans un projet donné. La capacité d’apprendre de nouveaux langages s’en trouve également augmentée ; mieux vous connaissez la grammaire de votre langue et plus il sera facile d’en apprendre une autre. Apprendre une seconde langue vous permettra aussi d’en savoir davantage sur la première.»

Concepts of Programming Languages, Robert W. Sebesta

Page 4: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 4

John Backus,

pionnier de l'inform

atique, publie en 1954 un article titré P

reliminary

Report,

Specifications for

the IB

M

Mathem

atical F

OR

mula

TR

AN

slating System

, FORTRAN. Il

fallut ensuite deux ans d'effort à l'équipe qu'il dirige

au sein

d'IBM

pour écrire

le prem

ier com

pilateur FORTRAN

(25 000

lignes, pour

l'IBM 704).

JOVIAL is

a com

puter program

ming

language sim

ilar to

ALGOL, but

specialized for the development of em

bedded systems. JO

VIA

L stands for

"Jules Own

Version

of the

International Algorithm

ic Language."

The

"International Algorithm

ic Language" part of the nam

e is from A

LGOL, w

hich was originally going to be called that (or IA

L for short). It w

as developed to write softw

are for the electronics of military aircraft by Jules Schw

artz in 1959. In the late 1970s and early 1980s, the U

.S. Air Force adopted a standardized

CPU

, the 1750A, and JO

VIA

L norm

ally produces programs for that processor.

Simula a été développé dans les années 1960 au N

orwegian C

omputing C

entre d'Oslo,

initialement par O

le-Johan Dahl et K

risten Nygaard. Syntaxiquem

ent parlant, c'est un sur ensem

ble d'Algol, qui ajoute à celui-ci les concepts, aujourd'hui fam

iliers, de la program

mation objet et de la sim

ulation discrète. Sim

ula a été conçu de façon à contenir des bibliothèques de classes offrant un support de

concepts spécifiques

à la sim

ulation discrète.

La

classe P

rocess, héritant

de Sim

ulation permettait ainsi à l'utilisateur d'hériter pour ses propres classes de sim

ulation du com

portement de base d'un processus pouvant s'exécuter en m

ode dit "quasi-parallèle", à l'aide du concept de coroutine.

Awk

est un

langage de

traitement de lignes disponible

sur UNIX

. Il agit com

me un

filtre (expressions régulières).

Pascal (de

Blaise Pascal)

a été conçu par Niklaus W

irth pour enseigner l’inform

atique de façon claire et rigoureuse.

Page 5: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 5

Page 6: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 6

JavaScrip

t a été créé en 1995 par Brendan E

ich pour Netscape C

ommunications C

orporation. Il est apparu pour la prem

ière fois dans les versions bêta de Netscape N

avigator 2.0. D'abord appelé L

iveScript, il a été rebaptisé JavaScript et est décrit comme un com

plément à Java

dans un communiqué de presse com

mun de N

etscape et Sun Microsystem

s (4 décembre 1995).

JavaScript est

aujourd'hui défini

par la

norme

ECMA-262,

aussi connue

sous l'appellation

ECMAScript. L

a troisième édition d'E

CMA-262 parue en 1999 correspond à la version 1.5 de

JavaScript. Son implém

entation par Microsoft porte quant à elle le nom

de JScript. Il est question d'une version JavaScript 1.6 supportée par la version 1.5 de Firefox. SpiderM

onkey est le nom de

l'implém

entation C du langage JavaScript utilisé dans G

ecko, le moteur de rendu développé par

mozilla. SpiderM

onkey est disponible sous la licence « MPL

/GPL

/LGPL

tri-license ».

Java est une technologie com

posée d'un langage de programmation

orienté objet

et d'un

environnement

d'exécution. Préalablem

ent nom

mé O

ak (en référence au chaîne planté devant le bureau), il a été créé chez Sun M

icrosystems. L

a plateforme et le langage sont issus

d'un projet de 1990. On com

mença par le Projet Stealth (furtif), qui

fut rebaptisé Green Project (J. G

osling, M. Sheridan, P. N

aughton).

Page 7: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 7

Tool

Command

Language,

généralement

abrégé en

Tcl,

est un

langage de programmation initialem

ent conçu

en 1989

pour le

système

d'exploitation UNIX

par

John Ousterhout et son équipe à l'U

niversité de

Berkeley.

Quelques

années plus

tard, une

extension graphique

est apparue, le T

k. Le développem

ent du Tk a suivi de près celui de T

cl pendant plusieurs années. Pour cette raison, on parle souvent de T

cl/Tk.

Perl

(Practical

Extraction

and R

eport L

anguage ou langage pratique d'extraction et de

génération de

rapports ; ce nom est un

rétro-acronyme)

est un

langage de

programmation créé par L

arry Wall en 1987 et

reprenant des fonctionnalités du langage C et

des langages de scripts sed, awk et shell (sh).

On écrit généralem

ent le nom de ce langage

avec un P m

ajuscule pour désigner le langage et un p m

inuscule en parlant de l'interpréteur : « seul perl analyse correctem

ent Perl. »

Python est un langage de program

mation

interprété, multi-paradigm

e. Il

autorise la

programmation

impérative

structurée, orientée objet, et fonctionnelle. Il est doté d'un typage dynam

ique fort, d'une gestion autom

atique de

la mém

oire par

ramasse-

miettes

et d'un

système

de gestion

d'exceptions. Créé en 1989 par G

uido van Rossum

, ce langage trouve l'origine de son nom

dans la série télévisée humoristique des

Monty Python.

Le C# (prononcé si sharp) est

un langage de programmation

orienté objet

à typage

fort, créé par la société M

icrosoft, et

notamment

un de

ses em

ployés, Anders H

ejlsberg. Il a été créé afin que la plate-form

e .NET soit dotée d'un

langage perm

ettant d'utiliser

toutes ses capacités. Il est très proche

du Java

dont il

reprend la

syntaxe générale

ainsi que les concepts.

Page 8: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 8

Chapitre 1

Questions fondamentales

I. Des langages pour quelles applications ?

Les ordinateurs sont utilisés dans de très nombreux domaines, du contrôle des centrales nucléaires au stockage de données personnelles. En raison de cette diversité, des langages d’utilisations avec des buts variés ont été développés. Nous allons donc montrer les principaux champs d’applications et certains langages associés.

1) Applications scientifiques Les premiers ordinateurs, apparus dans les années 40, étaient utilisés et même créées pour des applications scientifiques. Celles-ci ont typiquement besoin de structures de données simples (tableaux, matrices…) mais font beaucoup d’opérations arithmétiques en virgule flottante ; les structures de contrôle les plus courantes sont la boucle avec incrémentation et les sélections. Les langages de haut niveau inventés pour les applications scientifiques ont été conçus pour ces besoins ; ils sont en compétition avec l’assembleur, donc la performance était le critère principal. Le premier langage était FORTRAN. ALGOL 60 et la plupart de ses successeurs étaient aussi conçus pour être utilisé dans ce champ là, mais pas uniquement. Pour les applications où la performance reste le critère principal (calculs de physique, …), aucun langage n’est meilleur que FORTRAN.

2) Applications commerciales Les langages sont ici caractérisés par des capacités d’auto-documentation, de bonnes façons de décrire et stocker les types de données (décimaux et littéraux), et la gestion d’opérations mathématiques en virgule fixe. Avec l’avènement des micro-ordinateurs sont venus de nouvelles possibilités pour le commerce, en particulier les petits commerces, d’utiliser l’informatique. Deux outils spécifiques ont été développés pour le commerce sur les petits ordinateurs, et ils sont maintenant largement utilisés : les systèmes de bases de données, et les tableurs [spreadsheet systems, de ‘spread’ pour étendre, diffuser, s’étaler…]. COBOL (COmmon Business Oriented Language), né en 1960, reste encore le plus utilisé dans ce domaine ; en 2005, le Gartner Group estimait que 75% des données du monde des affaires étaient traitées par des programmes en COBOL et que 15% des nouveaux programmes développés le seront dans ce langage.

3) Pour l’intelligence artificielle Par « Intelligence Artificielle », on entend le vaste champ des applications caractérisées par l’utilisation de calcul symbolique plus que numérique. Autrement dit, on manipule des symboles (des noms) plutôt que des nombres, comme dans Maple. Habituellement, le calcul symbolique utilise des listes chaînées pour les données plutôt que des tableaux. Cette façon de faire a besoin de plus de flexibilité que d’autres domaines de la programmation. Par exemple, pouvoir créer et exécuter des blocs de code est utile [convenient : commode, pratique…]. Le premier langage vraiment utilisé dans ce contexte est LISP, apparu en 1959. La plupart des programmes d’intelligence artificielle ont été écrit en LISP ou dans un de ses dialectes. Durant les années 70, une approche alternative est apparue : la programmation logique en utilisant Prolog [Clocksin & Mellish, 1997]. Nous discuterons également de Scheme, un des dialectes majeurs de LISP.

Page 9: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 9

4) La programmation système Le système d’exploitation et tous les outils pour manipuler l’ordinateur sont appelés « programmes systèmes » [systems software]. Ils sont utilisés pratiquement en continue et doivent donc avoir une certaine rapidité d’exécution. Un langage pour ce domaine doit ainsi fournir une exécution rapide, et des capacités de bas-niveau pour faire les interfaces entre les programmes et les périphériques. Dans les années 60 et 70, quelques fabricants d’ordinateurs comme IBM, Digital et Burroughs (maintenant UNISYS) ont fait des langages de haut-niveau pour de la programmation système sur leurs machines. Pour IBM, le langage était PL/S, un dialecte de PL/I ; pour Digital, c’était BLISS, un langage à un niveau à peine au dessus de l’assembleur ; pour Burroughs, ce fut Extended ALGOL. Le système d’exploitation UNIX est écrit presque complètement en C (ANSI, 1989), ce qui a permit de faire des portages assez facilement d’une machine à une autre. Les caractéristiques de C en font un bon outil pour la programmation système : il est de bas niveau, avec une vitesse d’exécution performante, et il n’encombre pas l’utilisateur avec des sécurités. Les programmeurs systèmes sont en général de très bons programmeurs et ils ne pensent pas avoir besoin de restrictions ; ceux qui ne programment pas pour le système trouvent que C est trop dangereux à utiliser sur de gros et importants programmes systèmes.

5) Les langages de script Les langages de script ont évolué ces vingt dernières années. On les utilise en écrivant une liste de commandes (appelé script) dans un fichier qui sera exécuté. Le premier de ces langages était nommé sh (pour shell), consistant en un petit ensemble de commandes qui étaient interprétés comme des appels à des programmes systèmes réalisants des fonctions élémentaires [utility fonctions], comme la gestion d’un fichier ou le filtrage. On a ensuite ajouté des variables, des instructions de contrôle, des fonctions, et quelques autres possibilités qui en font un langage de programmation complet. Un des langages de script les plus avancés et connu est ksh [Bolsky & Korn, 1995] qui a été développé par David Korn aux laboratoires Bell. awk est un autre langage de script, développé par Al Aho, Brian Kernighan et Peter Wienberger aux laboratoires Bell ; il a commencé comme un langage spécialisé dans la production de rapports puis son but est devenu plus général. Tcl est un langage de script extensible développé par John Ousterhout à l’université de Berkeley (Californie) ; il est maintenant associé à tk, un langage permettant de construire des applications X-Windows. Le langage Perl, développé par Larry Wall, était tout d’abord une combinaison de sh et awk ; il a augmenté de façon significative depuis ses débuts et est maintenant un langage puissant bien qu’assez primitif. Sa popularité a cru avec Internet, puisque c’est un langage idéal à utiliser pour CGI (Common Gateway Interface). Javascript [Flanagan 1998] est un langage de script développé par Netscape pour être utilisé dans les serveurs et navigateurs Internet ; il a lui aussi prit en importance. En général, les langages de script ont peu contribués au développement de langages plus conventionnels. Cependant, Perl et Javascript ont certaines caractéristiques intéressantes que nous verrons par la suite.

6) Langages spécialisés Une foule de [host of] langages avec des buts bien précis sont apparus durant les 40 dernières années. Cela va de RPG (production de rapports commerciaux) à APT (piloter des machines-outils), en passant par GPSS (simulation des systèmes).

7) Attention à ne pas confondre Les langages à balises comme le HTML ne spécifient aucun calcul ; ils décrivent simplement l’apparence des documents. Ce ne sont pas des langages de programmation, bien qu’ils aient des critères communs !

Page 10: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 10

II. D’où vient la puissance d’un langage ?

Pour évaluer la puissance d’un langage, il faut se donner une liste de critères. Ils sont nécessairement sujets à controverse : considérer la valeur des caractéristiques d’un langage est assez subjectif. Néanmoins, les critères suivants sont généralement admis.

1) Lisibilité Il est important qu’un programme puisse être écrit et compris facilement. Avant 1970, le développement des programmes était surtout pensé en terme d’écriture du code. Dans les années 70, on a développé le concept du cycle de vie des programmes [Software life cycle concept, Booch 1987]. Coder devenait secondaire par rapport à la maintenance, surtout au niveau des coûts. La facilité de la maintenance venant en grande partie de la lisibilité des programmes, celle-ci est devenue primordiale dans la qualité des programmes et des langages de programmation. La lisibilité doit être placée dans le contexte du problème. Si un programme qui décrit des opérations n’a pas été écrit dans un langage fait pour ça, alors le programme peut être assez difficile à lire. Tout d’abord, il faut considérer la simplicité « générale » du langage. S’il a beaucoup de composants de base (nombreux mots réservés, …), ça peut le rendre plus difficile à lire. Les programmeurs qui doivent utiliser un gros langage n’en apprennent en général qu’un morceau et ignorent les autres possibilités. Une autre chose qui complique la lisibilité d’un langage est la « multiplicité » : pouvoir accomplir une opération particulière de différentes façons. Par exemple, en C on peut incrémenter un entier de quatre façons différentes : count = count + 1 count += 1 count ++ ++count Un troisième problème possible est la surcharge des opérateurs [operateur overloading], où le symbole d’un opérateur peut avoir plusieurs significations. Il est utile pour les utilisateurs d’être autorisés à surcharger, mais s’ils ne le font pas de façon raisonnable [sensibly], alors la lisibilité en est réduite. Par exemple, il est bien sûr acceptable de surcharger le + pour l’utiliser à la fois sur les entiers et sur les virgules flottantes ; cette surcharge va simplifier le langage en réduisant le nombre des opérateurs. Maintenant, imaginons que le programmeur défini un + utilisé entre sur un vecteur et signifiant la somme de tous les éléments : le programme risque d’être un peu confus. Et on peut utiliser le + par exemple pour faire la multiplication, ou pire encore… Il faut donc le faire à bon escient. Il ne faut pas non plus tomber dans une simplification à l’excès du langage. Par exemple, la forme et la signification de la plupart des instructions en assembleur sont des modèles de simplicité mais pour autant le langage est très difficile à lire. En effet, il faut quand même des instructions un peu plus complexes (des boucles par exemple), ainsi que la possibilité de construire des structures de données. L’orthogonalité [orthogonality] d’un langage de programmation signifie qu’un petit ensemble de primitives peuvent être combinées d’un petit nombre de manières pour fabriquer des instructions de contrôles et les structures de données du langage. Par exemple, regardons les types de données : imaginons un langage qui ait quatre types de données (entier, petit réel, grand réel, caractère), les tableaux et les pointeurs. Si ces deux opérateurs de type peuvent être appliqués à eux-mêmes et aux quatre types primitifs de données, alors on peut définir de très nombreuses structures de données ! Cependant, si les pointeurs ne peuvent pas pointer sur des tableaux, alors plusieurs de ces possibilités sont éliminées. On parle d’orthogonalité pour désigner une relation symétrique parmi les primitives. Les pointeurs devraient être capables de pointer sur n’importe quel type de variables ou de structures de données. Sinon on a un manque d’orthogonalité et cela entraîne des exceptions dans les règles du langage. On complique ! Attention à ne pas tomber dans l’excès. Le langage qui répond le plus à ce design est ALGOL 68 : le langage nécessite beaucoup de primitives, et son grand degré d’orthogonalité entraîne un nombre record de combinaisons possibles… Même si elles sont simples, ce nombre excessif entraîne de la complexité.

Page 11: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 11

En informatique, un ensemble d’instruction est dit ‘orthogonal’ si chaque instruction peut utiliser n’importe quel registre dans n’importe quel mode d’adressage. L’orthogonalité est une propriété du design qui permet de faire des systèmes complexes et compacts. Le but est de garantir que les opérations sur une des composantes du système ne vont pas créer ou propager des effets de bord sur les autres composantes. Par exemple, les composants et le contrôle d’une voiture réponde au design orthogonal : appuyer sur l’accélérateur n’influencera que les composants impliqués dans l’accélération. Si elle ne répondait pas à un design orthogonal, d’autres composants pourraient être affectés comme le volume de la radio ou l’affichage du temps… La révolution de la programmation structurée, dans les années 70, étant en partie une réaction à la lisibilité limitée entraînée par le manque d’instructions de contrôles dans les langages des années 50 et 60. En particulier, on a reconnu que l’usage abusif des instructions goto (sauter d’un point à un autre) réduisait nettement la lisibilité. Il était maintenant nécessaire que le programme puisse se lire de haut en bas et pas en jonglant d’un morceau à l’autre. Malgré cela, dans certains langages l’usage des ‘gotos’ est resté nécessaire : par exemple, on en a besoin en FORTRAN 77 pour construire les boucles ‘while’. Dans le pire des cas, les gotos doivent être en nombre limités, précéder leur cible et celle-ci ne doit pas être trop éloignée. La présence de certaines facilités pour définir des types et des structures de données est importante pour la lisibilité. Par exemple, imaginons un type numérique utilisé comme un indicateur parce qu’il n’y a pas de booléens (comme en C). On écrit alors timeOut = 1, ce qui est moins clair que timeOut = true. Grouper les composantes (penser aux Objets) aide également. Par exemple, si on veut des informations sur des employés et qu’on ne peut pas grouper, on se retrouve à manipuler 3 tableaux différents ; si quelqu’un prend la succession du code, il ne verra peut-être pas le lien évident, ou devra faire un effort. La syntaxe, ou la construction d’expressions grammaticalement correcte, est bien entendu primordiale. Il y a trois deux choix syntaxiques qui vont jouer sur la lisibilité :

- La taille des identificateurs. S’ils sont restreints à de très courtes tailles, il n’est pas possible d’utiliser des noms ‘qui parlent’. Par exemple, on a 6 caractères au maximum en FORTRAN 77…

- Les mots clés. L’aspect du code, et donc la lisibilité, dépend particulièrement de la forme des mots réservés du langage (par exemple while, class, for, …). La façon dont on fabrique les groupes d’instructions est importante : plusieurs langages utilisent des délimiteurs spéciaux ou des mots pour délimiter les groupes, comme Pascal qui construit ses blocs avec des begin-end (sauf pour le ‘repeat’ où cela peut-être oublié : un exemple du manque d’orthogonalité dans le design de Pascal). En C on fait appel aux accolades { }. Dans les deux cas on a un problème puisque les blocs se terminent tous de la même manière, et qu’on ne sait parfois plus trop à quel bloc appartient quelle accolade…

FORTRAN 90 et Ada permettent d’y voir un peu plus clair en utilisant des syntaxes de fermeture distinctes selon le type de bloc. Par exemple, Ada utilise end if et end loop. C’est un bel exemple de conflit entre la simplicité qui entraîne un faible nombre de mots clés (Pascal), et la plus grande lisibilité qui peut résulter d’un nombre de mots clés plus élevé comme en Ada. Notons enfin que selon les langages, les mots clés sont réservés ou non. Bien sûr, s’ils ne sont pas réservés alors le programmeur peut les utiliser pour n’importe quoi, comme en FORTRAN 90, ce qu’il faut absolument éviter…

Enfin, la sémantique (le sens des phrases) devrait s’inspirer de la forme pour que les choses soient bien claires. Ce principe est violé dès que le sens d’une expression s’inspire du contexte ; en C, static demande à créer la variable à la compilation, ou empêche qu’on l’exporte, selon qu’on soit dans/hors une fonction !

Page 12: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 12

2) Ecriture dans un langage Il faut aussi voir avec quelle facilité un langage peut-être utilisé pour écrire des programmes répondant à un problème donné. La plupart des caractéristiques qui affectent la lisibilité vont aussi toucher l’expression ; en effet, écrire un programme nécessite que le programmeur se relise fréquemment. Comme pour la lisibilité, la puissance d’expression doit être placée dans un contexte. Par exemple, on ne peut pas comparer COBOL et APL pour gérer des matrices, la spécialité de APL ; de même, la puissance d’expression du COBOL pour créer des rapports financiers complets n’est pas la même que APL. Un programmeur doit pouvoir construire la solution à un problème complexe en ayant appris seulement un petit ensemble de primitives. On déconseille toujours un grand nombre de composants de bases, méconnus par la plupart des gens ou utilisés de façon approximative. Attention cependant : les erreurs d’écriture peuvent ne pas être détectables quant n’importe quelle combinaison des primitives est possible. On peut écrire des codes absurdes qui resteront cachés au compilateur. L’abstraction est la capacité à définir et utiliser des structures complexes ou des opérations d’une façon où les détails sont ignorés. C’est un concept clé dans la conception des langages de programmation modernes. Le degré d’abstraction autorisé par un langage et l’écriture naturelle de ses expressions sont donc très importantes pour la puissance d’expression. Les langages peuvent avoir deux catégories d’abstraction, les processus et les données [abstraction of process and data]. Un simple exemple d’une abstraction sur les processus est l’utilisation de sous-programmes pour implémenter un algorithme de tri utilisé plusieurs fois par le programme. Sans ce sous-programme, le code aurait dû être écrit à tous les endroits requis. Le programme serait donc beaucoup plus long et délicat à lire puisque le code qui utilise l’algorithme de tri serait en désordre [would be cluttered] avec celui-ci. Pour un exemple d’abstraction des données, considérons un arbre binaire qui stocke des entiers dans ses nœuds. En FORTRAN 77, il serait implémenté comme trois tableaux parallèles d’entier, où deux des entiers sont utilisés pour spécifier les nœuds fils [to specify offspring nodes]. En C++ et Java, ces arbres pourraient être implémentés en utilisant une abstraction du nœud par une classe avec deux pointeurs et un entier. Le côté naturel [naturalness] de cette représentation permettra de l’utiliser facilement par la suite. La puissance d’expression fait référence à plusieurs caractéristiques. Dans un langage comme APL, cela signifie qu’il y a des combinaisons puissantes d’opérateurs qui permettent de faire de lourds calculs en un petit programme. Cela signifie plus couramment qu’un langage a des moyens relativement commodes [relatively convenient], plutôt qu’encombrants [rather than cumbersome] de spécifier les calculs. Par exemple, en C, la notation count++ est plus commode est courte que count = count + 1. De même, les opérateurs booléens and et then en Ada sont un moyen commode de décrire les évaluations d’une expression booléenne. L’utilisation de l’instruction for en Java permet d’écrire facilement des boucles d’incrémentation. Tout ceci augmente la facilité avec laquelle on écrit dans un langage. La fiabilité [reliability] est importante. Un programme est dit fiable s’il répond à ses spécifications en toutes conditions. La vérification du typage est un facteur important pour la fiabilité d’un langage. Cela consiste à tester les erreurs de type, par le compilateur ou durant l’exécution du programme. La vérification de type à l’exécution [run-time type checking] est très coûteuse, on préfère donc que le compilateur s’en charge. Plus tôt les erreurs de type sont détectées, et plus il est facile de faire les réparations adéquates. La conception de Ada a besoin d’une vérification des types de pratiquement toutes les variables et expression à la compilation, sauf quand l’utilisateur demande explicitement à ne pas le faire. Cela élimine virtuellement les erreurs de type à l’exécution sur les programmes en Ada. En revanche, le langage C originel [Kernighan & Ritchtie, 1978] est assez faible. Le type d’un paramètre lors de l’appel d’une fonction n’est pas vérifié pour déterminé si le type correspond bien à celui du paramètre formel de la fonction. On pouvait donc utiliser un type int pour une fonction attendant un float, et ni le compilateur ni le système ne détectent le problème. Voir l’utilitaire ‘lint’ sous UNIX pour un type checking en langage C.

Page 13: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 13

Par la manipulation des exceptions [exception handling], on entend l’habilité d’un programme à intercepter des erreurs à l’exécution, faire des corrections et reprendre le déroulement. Ada, C++ et Java ont de bonnes capacités pour cela, mais elles sont pratiquement inexistantes dans la plupart des langages largement utilisés comme C et FORTRAN. L’aliasing consiste à avoir plusieurs références sur la même case mémoire. C’est une capacité assez dure à gérer pour le programmeur, car les erreurs deviennent vite indétectables… Par exemple, en Scheme, on a une liste L et une sous-liste L1 : lorsqu’on modifie L1, cela modifiera la partie concernée de L, et on peut ne plus trop y songer. La plupart des langages fournissent une certaine dose d’aliasing. Par exemple en C, les unions, ou tout simplement des pointeurs sur la même adresse. Dans certains langages, on utilise l’aliasing pour compenser les manques concernant l’abstraction des données. D’autres langages restreignent l’aliasing afin de gagner en lisibilité.

Caractéristiques Lisibilité (readability) Ecriture (writabilité) Fiabilité (reliability) Simplicité et design orthogonal X X X

Structures de contrôle X X X

Types de données et structures X X X

Conception de la syntaxe X X X

Abstraction X X

Puissance d’expression X X

Vérification de type X

Gestion des exceptions X

Aliasing restreint X

Les caractéristiques qui affectent chacun des critères.

3) Les coûts Il faut apprendre aux programmeurs comment utiliser un langage, ce qui est fonction de la simplicité dudit langage et de l’expérience des programmeurs. Ensuite, il faut écrire des programmes dans ce langage, ce qui est fonction des capacités d’écritures du langage pour répondre au problème donné. Le coût de la formation et de l’écriture peut-être nettement réduit si on dispose de bons environnements. On songe alors au coût de la compilation pour le langage. Une des entraves [impediment] majeures quant à l’utilisation d’Ada était le coût de compilation prohibitif ; ce problème fut réduit par l’apparition de compilateurs plus performants. Enfin, il faut noter que le coût à l’exécution d’un programme dépend toujours du langage. Un langage qui fait beaucoup de vérifications de types à l’exécution empêchera d’avoir une exécution rapide, quelle que soit la qualité du compilateur. La rapidité d’exécution était la première inquiétude [foremost concern] dans le design des premiers langages, mais elle est maintenant considérée comme moins importante. Un simple compromis [trade-off] peut-être fait entre le coût de la compilation et la vitesse d’exécution du code compilé. « Optimisation » est le nom d’un ensemble de techniques que les compilateurs peuvent utiliser pour réduire la taille et/ou augmenter la vitesse d’exécution du code produit. Plus on optimise le code, et moins le compilateur va vite. On choisit selon le contexte : pour enseigner un langage, on préfère compiler rapidement puisque la compilation est courante mais les programmes ne sont en général exécutés qu’une fois ; dans un environnement professionnel, on portera l’effort sur l’optimisation. Bien entendu, il faut aussi penser au coût des implémentations. L’interpréteur Java est gratuit et marche sur la plupart des systèmes. Une implémentation chère ou utilisable seulement sur un matériel cher, est un frein à l’expansion du langage. La portabilité dépend du degré de standardisation (BASIC non-standard). Enfin, on pensera aux coûts dramatiques que peut avoir un langage qui n’est pas assez fiable, ainsi qu’aux coûts de maintenance (bien plus élevés que les coûts de développement sur de gros logiciels !).

Page 14: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 14

III. Quelles peuvent être les influences sur la conception ?

Les composantes centrales d’un langage impératif sont les variables (modélisent les cellules de la mémoire), les instruction d’affectations (représentent les transferts) et la boucle itérative. Les opérandes d’une expression sont transmises de la mémoire au processeur, et le résultat de l’évaluation va à la case mémoire représentée par le côté gauche de l’instruction. Par exemple, a = 3 * 4. Le processeur va calculer l’expression 3 * 4, puis on stocke le résultat dans la case mémoire représentée par l’adresse de a. L’itération est rapide dans une machine de Von Neumann puisque les instructions sont stockées dans des cellules mémoires adjacentes. Cette performance décourage l’utilisation de la récursivité pour faire des répétitions, bien que la démarche récursive soit souvent plus naturelle. Un langage fonctionnel (ou applicatif) est celui dans lequel la principale voie de calcul est l’application de fonctions à des paramètres donnés. On peut programmer en fonctionnel sans variable, ni affectations et sans les boucles itératives. Bien que qu’une multitude de scientifiques aient discutés [have expounded] des nombreux bénéfices de langages fonctionnels comme LISP, il est improbable [unlikely] qu’ils supplantent [displace] les langages impératifs… sauf si un ordinateur est conçu avec une architecture qui n’est pas celle de von-Neumann, pour permettre une exécution efficaces des programmes en fonctionnel. Parmi ceux qui déplorent [bemoaned] ce fait, John Backus, le principal designer du FORTRAN d’origine. Les architectures parallèles apparues dans les 20 dernières années ont tenues quelques unes des promesses pour améliorer la vitesse d’exécution des programmes en langages fonctionnels, mais ça n’est pas encore suffisant pour les rendre compétitifs avec les programmes impératifs. En fait, bien qu’il y ait des façons élégantes d’utiliser les architectures parallèles pour exécuter des programmes fonctionnels, la plupart de ces machines servent pour des programmes impératifs écrits dans des dialectes de FORTRAN… A la fin des années 70, un glissement d’une approche sur les processus à celle sur les données s’est opéré ; on s’est concentré sur l’utilisation de types abstraits de données pour résoudre les problèmes. Le premier langage proposant un support même limité à l’abstraction fut SIMULA 67. Les bénéfices de l’abstraction des données n’ont été reconnus pleinement qu’à la fin des années 70. La dernière étape fut la conception orientée objet, dans les années 80. L’approche orientée objet a été développée avec un langage qui en supportait les concepts : Smalltalk. La programmation orientée objet est maintenant dans la plupart des langages impératifs à la mode : Ada 95, Java, C++… Ces concepts ont aussi trouvés leur chemin dans la programmation fonctionnelle avec CLOS (Common Lisp Object System, primitives pour construire un programme orienté objet Common Lisp ; c.f. TinyClos en Scheme).

L’architecture de l’ordinateur a un effet très important sur le design du langage. La plupart des langages populaires des dernières 40 années ont été conçus autour de l’architecture dominante, nommée l’architecture Von Neumann (voir ci-contre). Cela a donné les langages impératifs. Dans un ordinateur de Von Neumann, les données et programmes sont stockés dans une même mémoire. Le processeur exécutant les instructions est séparé de la mémoire. Données et instructions transitent entre la mémoire et le processeur.

Page 15: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 15

IV. Quelques débats

1) Pensez-vous que nos capacités de pensées sont influencées par notre langage ? Nous discernons deux parties dans le langage : les mots, et leur agencement ; autrement dit, le vocabulaire et la grammaire, ou encore le lexical et le syntaxique. Le vocabulaire est totalement inféodé à la pensée ; une partie consiste à nommer des choses apparentes, tel un buisson ou un homme, et l’autre sert à désigner des concepts comme Dieu. Les concepts ne relèvent d’aucune application directe de la nature : ils ont donc nécessairement été pensé en premier lieu, avant de donner naissance à des termes. Le vocabulaire exerce une influence réciproque sur le langage, mais d’une importance modérée : il permet de synthétiser la pensée, et ainsi de gagner en rapidité. On peut exprimer les idées de « néant » ou « rien » sans connaître le mot, mais il faudra plus de temps en procédant par équivalences. Parfois, on perd également en précision ; par exemple, certaines peuplades contemporaines d’Amazonie ont des termes pour « un » et « deux », mais tout ce qui suit est regroupé sous un équivalent de « beaucoup ».

“The basic tool for the manipulation of reality is the manipulation of words. If you can control the meaning of words, you can control the people who must use the words.”

Philip Kindred Dick

En revanche, l’influence de la grammaire sur la langue est capitale. Un changement de langue, autrement dit une grammaire différente, entraîne une façon de penser différente. Regardons un exemple très classique : « tout ce qui brille n’est pas or ». La position de la négation dans la phrase est capitale pour en tirer le sens. Dans une autre langue, comme l’ésperanto, on aurait dit « Ne ĉio, kio brilas, estas oro », où le ‘Ne’ représente la négation ; on verrait immédiatement que c’est la négation de « tout ce qui brille est or ». De même, en informatique, la pensée est généralement récursive mais il arrive qu’on doive écrire un code qui est itératif. Cette façon d’agencer les choses, autrement dit cette grammaire, pose de nombreux problèmes et peut-être source d’erreurs.

2) Quels arguments avez-vous concernant un langage unique pour tous les domaines de programmation ?

Il serait bien plus facile de travailler en équipe et d’apprendre la programmation, puisque tous parleraient le même langage et que les exemples disponibles seraient tous accès dessus. On gagne donc sur le plan collaboratif et sur la formation. En revanche, le défi de trouver un langage adapté à toutes situations semble insurmontable. Tout d’abord, du simple point de vue de la langue : il y aura des situations où la formulation sera naturelle, et d’autre où elle ressemblera plutôt à une contorsion de l’esprit. Par exemple, si la démarche est fortement récursive mais qu’il faut l’exprimer de manière itérative ; ou encore que l’on veut faire des rapports financiers alors que l’on dispose en tout et pour tout de la gestion des entrées/sorties. La seule possibilité pour que le langage soit naturel dans toutes formes de situations, c’est qu’il y ait une variante pour chaque situation ; autrement dit, un langage unique viable ne peut-être qu’un méta-langage. Or, on perdrait là les intérêts énoncés au début : ce langage serait tellement gros que chacun ne pourrait plus en maîtriser qu’une facette… On se retrouverait dans la situation d’une langue trop complexe et d’une myriade de dialectes. En bref, il est préférable, et même naturel, d’avoir un langage ou dialecte pour un domaine en particulier.

Page 16: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 16

V. Qu’est-ce que la compilation ? L’analyseur syntaxique retrace le cheminement d’application des règles de syntaxe qui ont mené de l’axiome au texte analyse. Pour cela, il y a deux façons :

- Une analyse descendante. On part de l’axiome, et on tente d’appliquer les règles pour retrouver le texte. Pour cela, on coupe la phrase en éléments de plus en plus réduits jusqu’à arriver à des unités lexicales. Par exemple, l’analyse LL.

- Une analyse ascendante. On part du texte, et on tente d’associer des lexèmes en séquences de plus en plus larges jusqu’à retrouver l’axiome. Par exemple, l’analyse LR.

On produit un code intermédiaire, qui est parfois très proche des langages d’assembleurs contemporains, ou se situe un peu au dessus. L’optimisation, qui vise à rendre le programme plus petit et/ou rapide, est optionnelle ; en pratique, certains compilateurs en sont incapables. Enfin, la génération de code (partie la plus importante de la compilation) traduit le code intermédiaire, optimisé ou non, dans le langage de la machine cible.

Les langages de programmation peuvent être implémentés de plusieurs façons. Ils peuvent être traduits dans le langage de la machine (qui n’est pas nécessairement l’assembleur que nous connaissons !) pour une exécution directe. Cette façon de faire est celle du compilateur. Le programme s’exécute très rapidement une fois que le processus de traduction est effectué. Le langage prit par le compilateur est nommé ‘langage source’. La traduction se fait en plusieurs étapes. L’analyseur lexical rassemble les lettres du programme source en des unités lexicales, dits lexèmes : identificateurs, mots spéciaux, opérateurs, et symboles de ponctuation. L’analyseur lexical ignore les commentaires du code. On veut mettre en avant la structure de la phrase, pour voir de quelles façons les règles de syntaxe ont été combinées. Pour cela, l’analyseur syntaxique prend les lexèmes et construit des structures hiérarchiques : les arbres syntaxiques. Chaque nœud correspond à un opérateur, et les fils aux opérandes sur lequel il agit. On passe alors à l’analyse sémantique : on regarde si les combinaisons de règles sont valides, si la phrase a un sens. Cela permet par exemple de détecter les erreurs de type.

Page 17: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 17

La table de symboles est une structure servant de base de données pour la compilation. On y met au départ les types et attributs de toutes les variables définies par le programmeur. On s’en sert pour la génération de code et l’analyse sémantique, i.e. regarder s’il n’y a pas une erreur (de type le plus souvent). Bien que le programme en langage machine puisse être exécuté directement, il a souvent besoin de fonctionner avec d’autres parties. Ainsi, un programme peut faire appel à des fonctions du système d’exploitation (gestion des entrées/sorties), ou à des sous-programmes. Il faut lier tout ceci. Le compilateur construit des appels aux fonctions et sous-programmes. L’opération qui fait le lien place les adresses des points d’entrées des fonctions appelées lorsqu’il y a des appels. Avant, on désignait une fonction F, et maintenant on va physiquement la chercher. On désigne l’ensemble formé par le code système et celui du programmeur sous le nom de load module ou executable image. Le processus qui rassemble les programmes systèmes et fait le lien est nommé linking and loading, ou simplement linking. La tâche est réalisée par un programme système : le linker, ou l’éditeur de lien.

VI. Comment s’exécute le code ? Le processus qui exécute le code sur une machine de Von Neumann est nommé fetch-execution cycle (cycle de chargement et exécution). Comme nous l’avons vu, le programme réside en mémoire mais est exécuté par le CPU ; chaque instruction à exécuter doit donc aller de la mémoire dans le processeur. L’adresse de l’instruction suivante à exécuter est maintenue dans un registre nommé program counter (ou registre code, instruction address register, …). Il n’est pas manipulé comme un registre normal mais plutôt modifié à travers des instructions spéciales qui changent le flux de contrôle en y écrivant une nouvelle valeur, comme par exemple dans les commandes JUMP, CALL, RTS. Cette dernière, ReTurn from Subroutine, permet de revenir au programme principal après avoir exécuté un sous-programme ; le processeur mémorise le contenu du registre code dans la pile, le remplace par l’adresse du début de la sous-routine à exécuter, et arrivé à l’instruction RTS il récupère l’adresse mémorisée pour la remettre dans le registre code. De façon plus approfondie, cinq cycles sont habituellement nécessaires pour accomplir une instruction :

- IF (Instruction Fetch) : on charge l’instruction à exécuter depuis la mémoire - ID (Instruction Decode) : on décode l’instruction et on adresse les registres - EX (Execute) : on exécute l’instruction par la/les unités arithmétiques et logiques - MEM (Memory) : on transfère depuis le registre vers la mémoire (instruction STORE :

accès en écriture), ou de la mémoire vers le registre (instruction LOAD : accès en lecture). - W.B. (Write Back) : stocke le résultat de la mémoire ou d’un registre dans un registre.

Avec 5 cycles par instruction, il faut donc normalement 15 cycles pour exécuter 3 instructions. Mais si l’on insère des registres tampons (pipeline registers) entre chaque unité dans le processeur, il pourra contenir plusieurs instructions, chacune à une étape différente ! Sur l’exemple ci-contre, les 5 instructions s’exécuteront en 9 cycles alors que chacune d’entre elles a besoin de 5 cycles. C’est un pipeline à 5 étages : à t = 5, toutes les unités du processeur sont sollicitées.

Dans une architecture superscalaire, on multiplie le nombre d’unités du processeur et on peut exécuter plusieurs instructions en même temps. Sur un processeur superscalaire de degré 2, deux instructions sont chargées depuis la mémoire simultanément : en 9 cycles on peut exécuter 10 instructions (pipeline 5 étages). Aujourd’hui, tous les processeurs ont des pipeline ; le Intel 4 Prescott a une profondeur de 31 par exemple…

Page 18: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 18

VII. Quelles sont les autres manières d’exécuter un code ? Par ailleurs, l’interprétation pure a besoin de plus d’espace : en plus du programme source, la table des symboles doit être présente pendant l’interprétation… De plus, le programme sera plutôt stocké dans une structure centrée sur l’accès et la modification, que dans une structure qui veut minimiser la taille. Interpréter des programmes écrits dans un langage compliqué est une tâche délicate, car la signification de chaque expression et instruction doit être déterminée directement du code source lors de l’exécution… Les langages avec une structure simple (APL, LISP, …) se prêtent facilement à une interprétation pure. Les commandes système comme les scripts UNIX ou les fichiers .bat du DOS sont implémentés avec des interpréteurs. Par contre, des langages complexes comme FORTRAN ou C le sont rarement. Une exception : JavaScript est un langage compliqué, et il est pourtant interprété…

Une autre possibilité est de faire interpréter les programmes par un autre programme, nommé l’interpréteur ; c’est une simulation d’une machine, mais ses instructions sont de haut niveau. Comme cette machine n’existe pas, elle est dite machine virtuelle. Cette technique, dite de l’interprétation pure, ou interprétation simple, permet d’implémenter facilement des opérations de débuggeur au niveau du code ; par exemple, si l’index sort du tableau, un message d’erreur à l’exécution peut indiquer la ligne et le nom du tableau concerné. En revanche, exécuter un programme par un interpréteur est toujours plus lent qu’exécuter un programme compilé… En effet, il faut décoder des instructions de haut niveau, qui sont beaucoup plus complexes que les instructions en langage machine (même s’il y a moins d’instructions que leurs équivalents en langage machine).

Certaines implémentations des langages forment un compromis entre compilateurs et interpréteurs : ils traduisent le langage de haut niveau en un langage intermédiaire permettant une interprétation plus facile. Cette méthode est plus rapide qu’une interprétation pure car les instructions du langage source sont décodées une fois seulement. Il s’agit d’implémentations hybrides. Au lieu de traduire le code intermédiaire en code machine, on l’interprète. C’est l’implémentation retenue pour Perl ; c’est une évolution des langages purement interprétés sh et awk, mais partiellement compilé pour détecter les erreurs avant interprétation et simplifier. Les implémentations initiales de Java étaient toutes hybrides. Sa forme intermédiaire, nommée bytecode, permet la portabilité sur n’importe quel machine pourvue de l’interpréteur de byte code et d’un système pour l’exécution. L’ensemble est nommé la Java Virtual Machine (JVM). Il existe maintenant des systèmes qui transforment le bytecode en code machine : ce sont les compilateurs JIT (just-in-time), ou traducteurs dynamiques ; cependant, les applets Java restent téléchargés des pages web en bytecode. Parfois, celui qui fait l’implémentation peut proposer à la fois un compilateur et un interpréteur : on utilise l’interpréteur pour développer et débuguer, puis le compilateur pour distribuer le programme fini. Pour le bytecode, chaque instruction est codée sur un octet (byte) parfois suivi du nombre variables de paramètres, comme des registres ou des adresses. Dans les p-Codes, le codage peut être de plusieurs octets avec taille variable, tout comme certains opcodes (numéro qui caractérise l’instruction du processeur).

Page 19: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 19

Chapitre 2

L’évolution vue par les langages majeurs

I. Le Plankalkül de Konrad Zuse Plankalkül était remarquablement complet, notamment avec des fonctionnalités avancées en structures de données. Le type de base est le bit ; à partir de là, on peut construire des types pour les entiers et les nombres à virgule. En plus de ces types scalaires de base, Plankalkül comprenait les tableaux et les registres [records] ; les registres pouvaient utiliser la récursivité pour contenir d’autres registres en tant qu’éléments. Le langage n’avait pas l’instruction « goto », mais une instruction itérative similaire au ‘for’ de Ada. Il y avait également la commande « Fin », permettant de sauter d’un certain nombre d’itérations ou de se mettre au début d’un nouveau cycle d’itération. Il y avait aussi une instruction de sélection, mais elle n’incluait pas de clause « else » (traiter les données non sélectionnées). Une des caractéristiques les plus intéressantes est l’utilisation d’expressions mathématiques montrant les relations entre les variables du programme. Ces expressions affirment ce qui sera vrai à l’exécution, aux endroits du code où elles se trouvent. C’est très similaire aux assertions utilisées actuellement par le langage Eiffel et dans la axiomatic semantics. Le manuscrit de Zuse contenait des programmes nettement plus compliqués que ceux de son époque : trier des tableaux de nombre, tester si un graphe est connexe, effectuer des opérations sur les entiers et les réels comme la racine carrée… Il était également possible de faire une analyse syntaxique sur des formules logiques avec des parenthèses et des opérateurs à six niveaux de priorité [levels of precedence]. Zuse a également écrit un algorithme en 49 pages pour jouer aux échecs, bien qu’il ne soit pas expert. Si un informaticien avait trouvé la description de Plankalkül dans les années 50, la seule chose qui aurait empêché de l’implémenter [hindered its implementation] aurait été la notation. Chaque instruction consiste en deux ou trois lignes de code :

- la première comme les instructions de nos langages actuels - la seconde, optionnelle, contenait les indices [subscript] des tableaux référencés dans la

première ligne - la dernière ligne contient les types des objets manipulés par la première ligne

Le premier langage dont nous allons parler est assez atypique : il n’a jamais été implémenté. De plus, bien que développé dans les années 45, sa description ne parue qu’en 1972. Le scientifique allemand Konrad Zuse a construit entre 1936 et 1945 une série d’ordinateurs à partir de relais électromagnétiques. En 1945, la guerre détruisit tous ses modèles récents sauf un, le Z4. Il parti dans le village bavarois de Hinterstein. Travaillant seul, il se lança dans le développement d’un langage permettant d’exprimer les calculs, un projet qu’il avait commencé en 1943 comme projet pour sa thèse de doctorat. Il nomma son langage Plankalkül, ce qui signifie « programme de calcul ». Dans un long manuscrit de 1945, Zuse définit Plankalkül et écrit des algorithmes dans ce langage pour de nombreux problèmes.

| A + 1 => A V | 4 5 S | 1.n 1.n

On met la valeur de A[4] + 1 dans A[5]. Ici, 1.n signifie un entier de n bits. La ligne signifie V sert aux indices, et la S pour les types des données.

Page 20: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 20

II. Programmation machine minimaliste : Shortcode, Speedcoding, A-0 Les ordinateurs des années 40 et 50 étaient bien moins exploitables que ceux de maintenant : lents, peu fiables, coûteux, très petites mémoires, difficiles à programmer car ne disposant d’aucune base pour les programmes… Il n’y avait pas de langages de hauts niveaux ni même de langage d’assemblage, et la programmation était donc faite en code machine, ce qui est à la fois ennuyeux [tedious] et une source d’erreurs [error-prone]. On utilisait des nombres pour représenter les instructions : une instruction ADD était par exemple spécifiée par le code 14 au lieu d’un mot avec une signification explicite. Un autre problème était un adressage absolu au lieu d’un relatif, ce qui rend les programmes quasi-impossibles à modifier… En effet, le programme se réfère à des endroits du code ; si on ajoute ou supprime des instructions, l’endroit pointé ne va pas contenir ce qui était prévu ! Les seules façons de s’en sortir sont de rajouter les instructions en fin de programme, ou de trouver toutes les instructions qui se réfèrent à une adresse de la portion qui a changée pour les modifier à leur tour. Dans le cas de suppression, on éviter le problème plus facilement si le langage machine comprend une « opération neutre » qui peut remplacer celles supprimées. Tous ces problèmes étaient la motivation principale pour inventer les assembleurs et langages d’assemblage. La plupart des problèmes de programmation en ce temps étaient numériques, ils demandaient surtout l’arithmétique des réels et l’utilisation des tableaux. Comme aucune de ces capacités n’était incluse dans l’architecture des ordinateurs en ce temps-là, il a fallu des langages de plus haut niveau. L’instruction x0 = √|y0| se dit X0 = SQRT(ABS(Y0)) soit 00 X0 03 20 06 Y0. Si on la décompose, on a : 00 X0 03 20 06 Y0 Début du mot Variable x0 = √ | | Variable y0 Notons qu’il n’y avait pas de code pour la multiplication : il suffisait de placer les deux opérandes côte à côté, comme en algèbre. Short Code n’était pas transcrit en langage machine, mais implémenté avec une interprétation pure. On appelait alors ce processus « programmation automatique » : cela simplifiait nettement la programmation, mais nécessitait davantage de temps à l’exécution… L’interprétation du Short Code était à peu prêt 50 fois plus lente que le code machine.

Le premier de ces nouveaux langages, nommé Short Code, fut développé par John Mauchly en 1949 pour l’ordinateur BINAC. Le langage a ensuite été transféré dans un ordinateur UNIVAC I, et il a été le principal moyen de programmer ces machines pour bon nombre d’années. On connaît peu du Short Code d’origine car sa description n’a jamais été publiée, mais le manuel pour le UNIVAC I de 1952 a survécu. Short Code consistait en des versions codées d’expressions mathématiques qui étaient ensuite évaluées. Les codes étaient des paires d’octets, et la plupart des équations logeaient dans un mot (72 bits au maximum). Quelques instructions : 01 - 06 Valeur absolue 1n (n+2)n 02 ) 07 + 2n √(n+2)n 03 = 08 pause 4n if ≤ n 04 / 09 ( 58 afficher et insérer tabulation Les variables, ou les zones de la mémoire, étaient nommées avec une paire d’octet, et on utilisait l’emplacement en tant que constante. Par exemple, X0 ou Y0.

Page 21: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 21

III. L’IBM 704 et FORTRAN Une grande avancée dans l’informatique survint avec l’introduction de l’IBM 704 en 1954, dont les capacités ont poussé au développement de FORTRAN. Certains pourraient dire que s’il n’y avait pas eu IBM avec le 704 et le FORTRAN, d’autre société aurait fait un ordinateur similaire et un langage de haut niveau assimilable. Cependant, IBM fut le premier à prévoir les développements et à avoir les ressources nécessaires pour les assumer. Les systèmes d’interprétations étaient principalement utilisés à la fin des années 40, et début des années 50, pour pallier au manque d’arithmétique sur les réels dans les ordinateurs. Toutes les opérations en virgule flottante devaient être simulées par des programmes, ce qui consommait beaucoup de ressources. L’IBM 704 était pourvu d’instructions machines pour l’arithmétique sur les flottants, ce qui annonça [heralded] la fin de l’ère des interpréteurs, du moins pour le calcul scientifique. FORTRAN est souvent donné comme le premier langage de haut niveau compilé, mais les versions divergent pour savoir qui a fait la première implémentation d’un langage de ce type. Certains parlent de Alick E. Glennie pour son Autocode Compiler, destiné à l’ordinateur Mark I de Manchester ; ce compilateur a été développé à Fort Haltstead, Royal Armaments Research Establishment, en Angleterre. Il été opérationnel en septembre 1952 mais il était de tellement bas niveau et orienté machine qu’on ne peut pas vraiment le considérer comme un système de compilation.

Ailleurs, des systèmes d’interprétation ont été développés pour étendre le langage machine de sorte à ce qu’il gère les opérations sur les réels. L’interpréteur Speedcoding développé par John Backus converti l’IBM 701 en un calculateur à virgule flottante. Le système contient des pseudo-instructions pour les quatre opérations arithmétiques sur les réels, mais également la racine carrée, le sinus, l’arc tangent, l’exponentielle et le logarithme. L’architecture virtuelle possédait également les branchements et les conversions d’entrée/sortie. En revanche, la mémoire restante après le chargement de l’interpréteur était de seulement 700 mots, et une instruction ADD nécessitait 4,2 millisecondes. D’un autre côté, Speedcoding comprenait une nouvelle facilité : il incrémentait automatiquement l’address register.

Entre 1951 et 1953, une équipe menée par Grace Hopper chez UNIVAC a réalisé une série de systèmes pour la « compilation » nommés A-0, A-1 et A-2, qui développaient le pseudocode en code machine, de la même manière que les macros sont développés [expanded] en langage d’assemblage. Le pseudocode utilisé par ces « compilateurs » était assez primitif, mais c’était malgré tout un progrès important car cela permettait de rendre les programmes sources plus cours. Voir également les recherches à Cambridge dans le même temps de David J. Wheeler et Maurice J. Wilkes pour résoudre les problèmes d’adressage absolu.

Page 22: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 22

Le système de Laning et Zierler au M.I.T. fut le premier compilateur « algébrique », dans le sens où il pouvait accepter des formules mathématiques en notation algébrique et produire un code machine équivalente (utilisation d’appels à des fonctions pour les fonctions mathématiques, autorisation de noms de variables symboliques, allocation mémoire automatique, tableau et indexage). Le système fut réalisé de façon expérimentale sur l’ordinateur Whirlwind au M.I.T. dans l’été 1952, puis dans une forme plus utilisable en mai 1953. Le code source était facile à lire et les seules instructions machines utilisées étaient celles de branchement. Bien que ce travail précède celui sur FORTRAN, il n’est pas sorti du MIT. En dépit de ces travaux, le premier langage compilé de haut niveau qui fut largement accepté est FORTRAN. Avant même que le premier système IBM 704 soit annoncé en mai 1954, les choses étaient déjà préparées pour FORTRAN… En novembre 1954, John Backus et son groupe à IBM avaient fait un rapport nommé « The IBM Mathematical FORmula TRANslating System : FORTRAN ». Ce document décrivait la première version du langage, à laquelle on se réfère sous FORTRAN 0, avant même son implémentation. On insistait sur le fait que FORTRAN aurait l’efficacité des programmes codés ‘à la main’ et la facilité de programmer des systèmes interprétés ; dans un autre élan d’optimisme, le document stipulait que FORTRAN éliminerait les erreurs de code et n’aurait pas besoin de débuggeur. Partant de ce principe [based on this premise], le premier compilateur FORTRAN ne comprenait qu’un petit analyseur pour chercher les erreurs de syntaxe… Les caractéristiques de FORTRAN et des versions suivantes sont celles issues de son époque :

- Ordinateurs petits, lents et peu fiables - Utilisation principale des ordinateurs pour le calcul scientifique - Il n’existait pas de moyen véritablement efficace de programmer les ordinateurs - Les ordinateurs coûtent plus que les programmeurs, le code généré doit être rapide.

La période d’implémentation commença en Janvier 1955 et le compilateur fut prêt en Avril 1957. FORTRAN 0 fut modifié pendant cette période et ce qui fut implémenté est FORTRAN 1 ; il comprend des entrées/sorties formatées, des noms de variables jusqu’à 6 caractères (seulement 2 pour la version 0 !), des sous-programmes définis par l’utilisateur (mais qu’on ne peut pas compiler séparément), une instruction IF de sélection, et l’instruction DO pour faire des boucles. En FORTRAN 0, il y avait un IF logique dont l’expression (booléenne) utilisait des opérateurs relationnels sous forme algébrique, comme >. Or, l’IBM 704 ne comprenait pas ce genre de caractère, et il a donc fallu remplacer le IF logique par autre chose. La machine disposait d’une instruction de branchement à trois endroits possibles, basée sur la comparaison d’une variable stockée en mémoire avec une du registre. On se retrouve donc avec un IF arithmétique avec les trois branchements explicites : IF (arithmetic expression) N1 N2 N3 Si l’expression est négative, on va en N1 ; si elle est nulle on va en N2, et si elle est positive en N3. L’instruction de boucle itérative était la suivante : DO N1 variable = first_value , last_value Où N1 est le label de la dernière partie du corps de la boucle. Comme pour le IF, l’IBM 704 disposait d’une seule instruction pour implémenter le DO. Cette instruction était conçue pour des boucles avec un test à la fin, donc le DO de FORTRAN fut conçu en ce sens. On aurait pu faire des boucles avec un test au début, mais il aurait fallu une instruction machine supplémentaire ; comme le soucis majeur est la performance, cette boucle ne s’est pas faite. Toutes les instructions du FORTRAN I étaient basées sur celles de l’IBM 704, sans que l’on sache si ce sont les concepteurs du langage qui ont suggéré le design de la machine, ou l’inverse.

Page 23: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 23

Il n’y avait pas d’instruction pour typer les données en FORTRAN I. Les variables dont les noms commençaient par I, J, K, L, M et N étaient implicitement des entiers, et tout le reste des réels. Le choix de ces lettres vient du fait que les entiers étaient utilisés principalement en tant qu’indices, et que les scientifiques utilisaient i, j, k comme indices. Les concepteurs du langage ont autorisés 3 lettres de plus… Les plus audacieuses prétentions des concepteurs était que le code machine produit par leur compilateur serait aussi efficace que selon fait à la main. Ceci a rendu sceptique les utilisateurs potentiels, mais l’équipement de développement a pratiquement réussie son pari. La majeure partie du temps passé pour construire ce premier compilateur a été dépensé en optimisation. Une enquête d’avril 1958 montre qu’à peu prêt la moitié du code écrit pour des IBM 704 était fait en FORTRAN, en dépit de l’extrême scepticisme des programmeurs, seulement un an plus tôt !

Le compilateur FORTRAN II fut distribué au printemps 58, résolvant quelques unes des erreurs de son prédécesseur et proposant de nouvelles possibilités, comme la compilation indépendante des sous-programmes. C’est une évolution cruciale : en FORTRAN I, un changement dans une partie du programme nécessitait de le compiler entièrement à nouveau ; quand on ajoute à ceci le manque de fiabilité des IBM 704, on comprend qu’il y avait une restriction en pratique de 300 ou 400 lignes de programme. Si on poussait au-delà, on avait peu de chance d’arriver à compiler complètement le programme sans que la machine plante… Un FORTRAN III fut développé mais peu diffusé. FORTRAN IV, en revanche, devint un des langages les plus utilisés de son époque. Il a évolué de 60 à 62, et était la version standard (jusqu’à la norme ANSI en 1978). Parmi les grandes nouveautés on trouve le typage explicite des variables, un IF logique, et la possibilité de passer des sous-programmes comme paramètres à d’autres sous-programmes ! Le FORTRAN 77 (résultant de la norme ANSI) rajoute une clause optionnelle ELSE au IF, une instruction pour contrôle une boucle avec une expression logique, et la manipulation des chaînes de caractère [character string handling].

FORTRAN 90 (ANSI, 1992) est le nom de la dernière version, très différente du FORTRAN 77. Un ensemble de fonctions est fourni d’origine pour la manipulation des tableaux (dotproduct, matmul, transpose, maxval, minval, product, sum, …), et la gestion en mémoire des tableaux peut être dynamique s’ils ont été déclarés avec le qualificatif allocatable. C’est un changement important par rapport aux FORTRAN précédents, qui avaient seulement des données statiques. Les pointeurs font également leur apparition. De nouvelles instructions de contrôles sont incluses : case (sélection multiple), exit (sortie d’une boucle), cycle… Les sous-programmes peuvent être récursif avec des paramètres optionnels. FORTRAN 90 introduit également la notion de modules, similaire aux packages en Ada. Les modules peuvent contenir la déclaration des données et des sous programmes, chacun pouvant être private ou public, pour contrôler les accès. Un nouveau concept dans la définition de FORTRAN 90 est la suppression de certaines choses dans les langages des versions précédentes. Bien que FORTRAN 90 contienne tout de FORTRAN 77, il y a deux listes de choses à éliminer dans les versions à venir. La liste des choses « obsolètes » est une suppression planifiée pour la prochaine version, avec le IF arithmétique et les instructions GOTO. La seconde liste contient les choses dépréciées comme COMMON et EQUIVALENCE.

Page 24: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 24

IV. La programmation fonctionnelle : IPL, FLPL, LISP, ML, Miranda Le premier langage de programmation fonctionnelle a été inventé pour le traitement des listes, besoin grandissant dans les applications d’intelligence artificielle. Les intérêts en IA ont commencé à apparaître au milieu des années 50 en de nombreux domaines : linguistique (traitement de la langue), psychologie (modéliser le stockage et la recherche des informations dans le cerveau humain), mathématiques (automatiser certaines tâches ‘intelligentes’ comme la preuve de théorèmes)… Toutes ces investigations arrivèrent à la conclusion qu’il fallait développer des méthodes afin que les ordinateurs puissent traiter des données symboliques, en des ‘listes chaînées’ [linked lists]. En ce temps là, tous les calculs étaient sur des données numériques, stockées dans des tableaux… Le concept de traitement des listes a été développé par Allen Newell, J. C. Shaw et Herbert Simon. Il fut d’abord publié dans un article de 1956 qui décrivait l’un des premiers programmes d’intelligence artificielle, the Logical Theorist, avec un langage dans lequel implémenter le programme. Ce langage était nommé IPL-I (Information Processing Language I), et ne fut jamais implémenté. La version IPL-II fut mise en place sur un ordinateur Johnniac de la Rand Corporation (research and development, armée USA). Le développement continua jusqu’en 1960, où la description de IPL-V fut publiée. Le côté « bas niveau » des langages IPL ne permet pas d’en avoir un usage répandu [prevented their widespread use]. Il s’agissait plutôt de langages d’assemblage pour un ordinateur hypothétique, implémenté par un interpréteur, dans lequel des instructions pour le traitement des listes étaient incluses. Le fait que la première implémentation soit sur une machine Johnniac a gardé les langages IPL loin du grand public… L’intérêt a été de montrer la faisabilité et l’importance du traitement des listes, avec un design léger. IBM a commencé à s’intéresser à l’intelligence artificielle au milieu des années 50, et a choisit la preuve de théorèmes. Comme un compilateur FORTRAN I coûtait déjà très cher, IBM a été convaincu que leur traitement des listes devait être une extension de FORTRAN et non un nouveau langage. Par conséquent, ils ont développés le FORTRAN List Processing Language (FLPL), utilisé pour construire un logiciel qui prouvait des théorèmes en géométrie plane, ce qui était alors le champ d’investigation le plus simple pour la preuve automatique de théorèmes [mechanical theorem proving]. John McCarthy du MIT travailla durant un été au département de la recherche d’IBM. Son but était d’explorer le calcul symbolique, et de poser l’ensemble des choses nécessaires pour faire ces calculs. Comme exemple pilote, il s’est intéressé à la possibilité de différencier des expressions algébriques. De là est venu un ensemble de caractéristiques nécessaires dans le langage : contrôler des méthodes mathématiques avec de la récursivité et des expressions conditionnelles. Le seul langage de haut niveau était alors FORTRAN, qui n’avait pas les caractéristiques requises. Un autre besoin de la différentiation symbolique était l’allocation dynamique de listes, et une libération automatique en mémoire des listes abandonnées. McCarthy ne voulait simplement pas que son algorithme élégant de différentiation se trouve en désordre avec des instructions explicites de dé-allocation. FLPL ne supportait ni récursivité, ni expressions conditionnelles, ni allocation dynamique et dé-allocation implicite. Il fallait donc un nouveau langage. Quand McCarthy est retourné au MIT, à l’automne 1958, il a fondé avec Marvin Minsky le projet d’intelligence artificielle, avec les fonds du laboratoire d’électronique. Le premier but du projet a été de produire un système pour le traitement des listes, qui devait être utilisé au départ pour implémenter un programme de McCarthy nommé Advice Taker (‘preneur de conseil’). Cette application a lancé le développement du langage LISP. Sa première version est parfois nommée « LISP pur » car il s’agit d’un langage purement fonctionnel, avec seulement deux types de structures de données : l’atome (symboles ou nombres) et la liste. L’idée de stocker des informations dans des listes chaînées est naturelle, déjà utilisée dans IPL-II ; on peut insérer et supprimer en tout point de la liste.

Page 25: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 25

LISP est un langage de programmation fonctionnelle, ce qui signifie que tous les calculs du programme sont fait en appliquant des fonctions à des arguments. Il n’y a pas besoin d’affectation ni de variables, et les boucles ne sont pas nécessaires puisqu’il s’agit de cas particulier de récursivité. Ces concepts de base de la programmation fonctionnelle en font quelque chose de très différent de celle impérative, classique.

Tandis que la syntaxe de C est un assemblage d’anglais et d’algèbre, celle de LISP est un modèle de simplicité. Le code et les données ont exactement la même forme : des listes avec parenthèses. La liste (A B C D) est la donnée constituée de quatre atomes ou aussi l’application de A aux arguments B, C, D. LISP a totalement dominé le monde de l’intelligence artificielle pendant 25 ans, et il reste le plus utilisé. La plupart des causes qui lui conféraient la réputation d’être lent sont maintenant éliminées ; de nombreuses implémentations contemporaines sont compilées, et le code résultat est bien plus rapide que celui qui passe par un interpréteur. En plus de son succès en intelligence artificielle, LISP était un des premiers langages de programmation fonctionnelle, ce qui est devenu un sujet de recherche très actif en langages de programmation. En effet, de nombreux chercheurs pensent que l’approche fonctionnelle est bien meilleure pour le développement des programmes que celle avec les langages impératifs. Durant les années 70 et 80, de très nombreux dialectes de LISP ont été développés et utilisés, qui a mené à un problème de portabilité. Pour rectifier la situation, une version standard nommée COMMON LISP a été développée. Parmi les deux dialectes majeurs, on trouve donc COMMON LISP mais aussi Scheme. Scheme a émergé du MIT au milieu des années 70. Les fonctions y sont traitées comme des éléments de première classe : elles peuvent être la valeur d’expressions, ou le contenu de listes. Elles peuvent être passées en paramètres, ou retournées comme le résultat de l’application de fonctions. Comme COMMON LISP tente de réunir tous les dialectes, il est assez large et complexe. Sa base reste du LISP pur, donc sa syntaxe et ses primitives viennent de ce langage. Il dispose de très nombreuses structures de données et types, comme les tableaux, les complexes et les chaînes ; il dispose également du concept de packages pour rendre modulaire des ensembles de fonctions et données, en fournissant une gestion des accès. Notons que Scheme dispose maintenant des mêmes possibilités. ML (MetaLanguage) a été conçu dans les années 80 par Robin Milner à l’université d’Edinburgh, pour un système de vérification de programmes nommé Logic for Computable Functions (MCF). ML est surtout un langage fonctionnel, mais il supporte également de la programmation impérative. Les fonctions y sont couramment passées en tant que paramètre, et peuvent être polymorphiques : les paramètres des fonctions peuvent être de différents types dans différents appels. Le type de chaque variable est expression peut être déterminé à la compilation, à partir du contexte. ML n’a pas de parenthèses ; il est plus proche de C++… Miranda a été développé par David Turner à l’université du Kent à la fin des années 80, basé partiellement sur les langages ML, SASL et KRC. Haskell est basé principalement sur Miranda : c’est un langage purement fonctionnel, sans variable ni affectation. Il utilise une lazy evaluation : l’expression n’est évaluée que lorsque sa valeur est utile.

Les listes sont spécifiées avec des parenthèses. Par exemple, dans une liste où les éléments sont réduits à des atomes, on a : (A B C D). Il y a aussi des structures de listes emboîtées [nested list structure] : (A (B C) D (E (F G))) est composé de 4 éléments, qui sont l’atome A, la liste (B C), l’atome D, et la liste (E (F G)), elle-même formée d’un atome et d’une liste.

Page 26: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 26

V. Une première étape vers la maturité : ALGOL 60 A la fin 1954, le système algébrique de Laning et Zierler était en service depuis un an, et le premier rapport sur FORTRAN était publié. FORTRAN devint une réalité en 1957 et plusieurs autres langages de haut niveau furent développés. Parmi les plus notables on trouve IT (Alan Perlis de Carneghie), et deux langages pour les ordinateurs UNIVAC : MATH-MATIC et UNICODE. La prolifération des langages commençait à rendre la communication entre les utilisateurs de plus en plus délicate… De plus, ces nouveaux langages étaient chacun orientés vers des architectures bien précises : les ordinateurs UNIVAC ou les IBM de la série 700. En réponse à la prolifération des langages, certains des principaux groupes d’utilisateurs de l’informatique aux Etats-Unis se sont réunis en un comité pour créer un langage de programmation universel. On trouve parmi eux SHARE (les scientifiques qui utilisent les machines IBM) et USE (les scientifiques qui utilisent les machines UNIVAC). Déjà en 1955, GAM (acronyme allemand pour Société de Mathématiques Appliqués et Mécanique) avait formé un comité pour concevoir un langage algorithmique universel, indépendant des machines. Le besoin provenait surtout de la peur des européens d’être dominés par IBM. Cependant, à la fin 1957, l’apparition de plusieurs langages de haut niveau aux Etats-Unis a convaincu le GAMM qu’il allait falloir travailler avec les américains. En avril 1958, les deux groupes se réunirent. La réunion de Zurich (mai-juin 1958) commença avec les buts suivants pour le nouveau langage :

- Syntaxe la plus proche possible des notations mathématiques (utilisation du langage pour le calcul scientifique, principal domaine de l’époque)

- Les programmes doivent être compréhensibles avec de courtes explications seulement - Il doit être possible d’utiliser le langage pour décrire des calculs dans les publications - Les programmes doivent pouvoir être transcrits mécaniquement en langage machine

(une nécessité pour tout langage de programmation…) La réunion a produit d’innumérables compromis, parfois peu utiles, comme savoir s’il fallait utiliser un ‘,’ ou un ‘.’ dans la notation des décimaux. Le langage qui en résulta fut nommé International Algorithmic Language (IAL). Il fut suggéré de le nommer ALGOL (ALGOrithmic Language) mais le nom fut rejeté. Finalement, le nom d’ALGOL fut adopté l’année suivante et le langage fut donc connu sous ALGOL 58. Sous de nombreux aspects, ALGOL était un descendant de FORTRAN, ce qui est assez logique. Il a généralisé plusieurs aspects de FORTRAN tout en rajoutant de nouveaux concepts. Certaines des généralisations étaient relatives au fait qu’il ne fallait pas lier le langage avec une machine particulière, et d’autres voulaient rendre le langage plus flexible et puissant. Certaines généralisations sont les suivantes :

- les identificateurs peuvent avoir n’importe quelle taille (au lieu de 6) - un tableau à n’importe quelle dimension était autorisé (au lieu de 3 dimensions) - la borne inférieure des tableaux était paramétrable (en FORTRAN, obligatoirement 1) - des sélections emboîtées étaient possibles

ALGOL 58 a formalisé le concept de type de données, bien que les seules variables qui n’étaient pas des réels nécessitaient une déclaration explicite. L’opérateur d’affectation est un peu plus particulier. Même si la description de Plankalkül n’avait pas encore été publiée, certains des membres européens du comité connaissaient le langage. En Plankalkül, on utilisait expression => variable. Les américains imposèrent la forme variable := expression (qu’on retrouve maintenant en Maple pour différencier du = des équations). La publication du rapport sur ALGOL 58 en décembre fut accueillie avec beaucoup d’enthousiasme. Aux Etats-Unis, le nouveau langage était vu plutôt comme une collection d’idées que comme un langage universel… Ce rapport n’était pas censé être quelque chose de fini, mais plus un document préliminaire ouvrant les discussions. Néanmoins, trois implémentations majeures utilisèrent ce rapport comme base.

Page 27: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 27

A l’université du Michigan, le langage MAD était né. Le groupe d’électronique naval de l’armée produisit le langage NELIAC. A System Development Corporation, le langage JOVIAL fut conçu et implémenté ; il s’agit d’un acronyme pour Jules’ Own Version of the International Algebraic Language. JOVIAL fut le seul langage basé sur ALGOL 58 à parvenir à une diffusion importante, principalement parce que c’était le langage scientifique officiel pour l’Air Force pendant 25 ans. Le reste de la communauté des informaticiens aux Etats-Unis n’était pas aussi enthousiaste. Au départ, IBM et ses principaux groupes d’utilisateurs (SHARE), ont semblé accepté ALGOL ; IBM a démarré une implémentation peu après la sortie du rapport, et SHARE a formé un sous-comité SHARE IAL pour étudier le langage. Ce sous-comité recommanda par la suite [subsequantly] de standardiser ALGOL 58, et qu’IBM l’implémente pour tous ses ordinateurs de la série 700. Cependant, l’enthousiasme fut de courte durée… En 1959, IBM et SHARE, par leur expérience du FORTRAN, en eurent assez des dépenses qu’entraînait la création d’un nouveau langage, autant en terme de développement des compilateurs que de formations des utilisateurs. Ils avaient développé un tel intérêt en FORTRAN qu’ils décidèrent d’en faire le langage scientifique pour leurs ordinateurs, et abandonnèrent de ce fait ALGOL 58. En 1959, il y a eu de nombreux débats sur ALGOL 58 en Europe

et aux Etats-Unis. Un grand nombre des modifications suggérées et de rajouts furent publiés dans le bulletin européen sur ALGOL, et dans le Communications of the ACM. En janvier 1960, le second débat sur ALGOL se tint à Paris, pour débattre de 80 suggestions. Bien que ce meeting ne dure que 6 jours, les modifications effectuées furent radicales :

- Introduction du concept de structures par blocs. On arrive à des programmes locaux avec de nouveaux environnements pour les données, et de nouvelles portées [scopes].

- Deux moyens différents de passer des paramètres aux sous-programmes : passage par valeur, et passage par nom (référence).

- Les procédures peuvent être récursives (pas une nouveauté, avec LISP en 1959…).

- Des tableaux « dynamiques » sont autorisés : leurs bornes sont spécifiées par des variables, donc la taille du tableau est déterminée au moment où l’allocation mémoire s’effectue. On les nomme stack-dynamic arrays.

De nombreuses autres choses importantes furent rejetées, comme le formatage des entrées/sorties, qu’on jugeait alors trop dépendant des machines. Le rapport fut publié en mai 1960, et un meeting eu lieu à Rome en avril 1962 pour lever certaines des ambiguïtés qu’il contenait (sans rajout de fonctionnalités). Ce troisième meeting donna le Revised Report on the Algorithmic Language ALGOL 60. ALGOL 60 a réussi à devenir, presque immédiatement, le seul moyen formel de communiquer des algorithmes dans la littérature, et il est resté pendant 20 ans le seul langage pour la publication des algorithmes. Chaque langage impératif depuis 1960 possède un peu d’ALGOL 60… Ce langage est le premier dont la syntaxe fut décrite de façon formelle, à l’aide du formalisme BNF. Cette réussite dans l’utilisation du BNF initia plusieurs champs importants de l’informatique : les langages formels, l’analyse, le design des compilateurs… Finalement, la structure du langage a même affecté l’architecture des machines : une extension a été utilisé comme langage système pour une série de gros ordinateurs, les Burroughs B5000, B6000 et B7000, conçus avec une pile physique pour implémenter de façon efficace la structure en blocs et les procédures récursives.

Page 28: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 28

VI. Le Business et l’informatique : COBOL COBOL est probablement un des langages les plus utilisés, mais il a eu peu d’effet sur le design des langages ultérieurs, en parti parce que peu ont tenté de concevoir un langage pour les applications commerciales depuis son apparition. Les capacités de COBOL sont bien conçues pour son champ d’application, et la principale augmentation dans le business sur ordinateur est faite par les petites sociétés qui utilisent des solutions toutes prêtes. En 1959, il y avait un langage compilé pour les applications commerciales, nommé FLOW-MATIC, mais il appartenait à Univac et était conçu pour les ordinateurs de la compagnie. Un autre langage, AIMACO, avait commencé à être utilisé par la Air Force, mais c’était une simple variation de FLOW-MATIC. IBM avait également conçu son langage COMTRAN (Commercial Translator), mais pas encore implémenté. En décembre 1953, Grace Hopper a formulé une proposition qui suggérait que « les programmes mathématiques doivent être écrits avec une notation mathématique, les programmes de gestion de données doivent être écrits avec des instructions en anglais ». Hélas, il était impossible en 1953 de convaincre des non-programmeurs qu’un ordinateur pouvait être conçu de sorte à comprendre des mots en anglais… En 1955, un prototype fut conçu qui compilait et lançait un petit programme, utilisait des mots-clés en Anglais, puis en Français, et enfin en Allemand. Cette démonstration fut considérée comme remarquable par la direction d’UNIVAC, et fut déterminant pour accepter la proposition de G. Hopper. La première réunion visant à construire un langage commun pour les applications commerciales eu lieu au Pentagone en mai 1959. Le consensus du groupe fut que le langage, alors nommé CBL (pour Common Business Language) devait être centré sur la facilité. Pour cela, on utilise l’anglais autant que possible, d’une façon simple même si cela doit rendre le langage moins puissant. Cela permettrait d’élargir le public des programmeurs, et les managers pourraient lire les programmes. Il fallait que ce langage soit fait rapidement, comme RCA et Sylvania étaient en train de développer leurs propres langages ; si un langage universel n’était pas vite conçu, il serait trop tard pour qu’il s’impose. Pour cela, il fut décider qu’il devrait y avoir une étude rapide des langages existants ; le Short Range Committee fut formé dans ce but. Il fut décidé dès le début de séparer les instructions du langage en deux catégories : description des données et opérations exécutables. Les instructions pour ces deux catégories doivent être en des endroits différents du programme. Le rapport final du comité, complété en décembre 1959, décrivit un langage qui fut nommé ultérieurement COBOL 60. Des versions révisées furent publiées en 1961 et 1962, toujours par le département de la défense. Le langage fut standardisé par l’ANSI en 1968. Les deux révisions suivantes furent standardisées en 1974 et 1985. Le langage continue d’évoluer de nos jours.

Le langage COBOL a amené de nouveaux concepts, dont certains se retrouvent dans d’autres langages. Par exemple, le verbe define fut la première instruction dans les langages de haut niveau pour les macros. Plus important, les structures de données hiérarchiques, d’abord apparues dans Plankalkül, furent implémentées en COBOL ; elles ont été inclues dans pratiquement tous les langages impératifs depuis. COBOL était également le premier langage à autoriser des noms vraiment explicites, parce qu’il autorisait qu’ils soient à la fois long (30 caractères) et connectés par des tirets. La partie sur les données est le point fort de la conception, où chaque variable est décrite en détail, y compris le nombre de digits et l’endroit de la virgule. Les fichiers sont également bien décrits, comme les lignes à envoyer à l’imprimante, ce qui fait de COBOL le langage idéal pour imprimer des documents du business. En revanche la partie sur les procédures est assez faible, principalement parce qu’elle manque de fonctions ; avant le COBOL de 1974, il n’y avait pas de sous-programmes avec paramètres.

Page 29: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 29

↑ Le programme ci-dessus lit un fichier nommé BAL-FWD-FILE qui contient l’inventaire sur certains objets. Chaque objet enregistré contient un nombre courant disponible BAL-ON-HAND, et le nombre d’objet minimale en stock BAL-REORDER-POINT où l’on doit faire un réassort. Le programme produit la liste des objets sur lesquels il y a un réassort dans le fichier REORDER-LISTING.

000100 IDENTIFICATION DIVISION. 000200 PROGRAM-ID. SALUTTOUS. 000300 DATE-WRITTEN. 21/05/05 19:04. 000400 AUTHOR. 000500 ENVIRONMENT DIVISION. 000600 CONFIGURATION SECTION. 000700 SOURCE-COMPUTER. RM-COBOL. 000800 OBJECT-COMPUTER. RM-COBOL. 000900 001000 DATA DIVISION. 001100 FILE SECTION. 001200 100000 PROCEDURE DIVISION. 100100 100200 DEBUT. 100300 DISPLAY " " LINE 1 POSITION 1 ERASE EOS. 100400 DISPLAY "BONJOUR !" LINE 15 POSITION 10. 100500 STOP RUN.

← Le programme ci-contre affiche simplement ‘bonjour’, dans le style typique des programmes sur cartes perforées des années 60-70. On remarque la division pour les données, avec la section pour les fichiers ; puis la division pour les fonctions, où on affiche. ↓ Le même exemple en COBOL 85 format libre.

Identification division. Program-id. Hello. Procedure division. Display "Hello world!". Stop run.

Page 30: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 30

VII. La simplicité : BASIC Le BASIC est assez simple à apprendre pour les débutants, surtout pour ceux qui ne sont pas de la science, et son dialecte réduit lui permet d’être implémenté sur des ordinateurs avec des petites mémoires. Le BASIC (Beginner’s All-purpose Symbolic Instruction Code) fut conçu au Darmouth College (maintenant une université) par les mathématiciens John Kemeny et Thomas Kurtz, dont les étudiants avaient des difficultés avec les langages FORTRAN et ALGOL 60. Comme le corps étudiant était surtout composé par ceux en sciences humaines, le langage fut conçu en particulier pour eux. Les buts étaient :

- simplicité pour les étudiants non-scientifiques à apprendre et utiliser - un langage assez ‘plaisant et sympathique’ - doit être assez rapide à exécuter pour faire ses devoirs - gestion des accès (vue en temps que terminal) - considérer le temps utilisateur plus important que celui de la compilation

Il y a dans ce dernier but une révolution : considérer que les ordinateurs deviendraient de moins en moins chers avec le temps et plus performants, d’où une centralisation sur l’utilisateur. L’accès était fait par des terminaux : en juin 1964 il y en avait 11, et à la fin de l’automne on était passé à 20. Dans la première version de BASIC, il n’y avait pas d’interactivité : le terminal ne prenait pas d’entrée. Les programmes étaient tapés, compilés et exécutés, sans pouvoir demander de valeurs à l’utilisateur. Il y avait 14 instructions différentes et le seul type de données était les réels. Comme on pensait que les utilisateurs ciblés ne seraient pas capables de différencier des entiers de réels, le seul type disponible était désigné sous le qualificatif « numbers ». C’était un langage extrêmement limité, mais rapide à apprendre… Le BASIC était la première méthode vraiment utilisée pour accéder à un ordinateur distant par le biais de terminaux, qui commençaient juste à devenir disponibles. Avant, la plupart des programmes étaient donnés aux ordinateurs par des cartes perforées ou des bandes perforées [puncher card or paper tape]. Le gros du design vient de FORTRAN avec un peu d’influence sur la syntaxe de ALGOL 60. Plus tard, le langage s’est dispersé en une myriade de dialecte, sans aucune volonté de standardisation. Il y eu un standard ANSI en 1978 mais qui représentait juste le strict minimum des capacités du langage.

Digital Equipment Corporation utilisa le BASIC dans une version améliorée nommée BASIC-PLUS pour écrire de grosses portions de leur plus gros système d’exploitation RSTS pour les mini-ordinateurs PDP-11 dans les années 1970. Deux des versions contemporaines du BASIC très utilisées sont QuickBASIC de Bradley, et le VisualBASIC de Microsoft.

Page 31: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 31

VIII. Tout pour tout le monde : PL/I

Dans les années 60, les utilisateurs d’informatique dans l’industrie étaient en deux camps. Les programmeurs scientifiques pouvaient utiliser le gros ordinateur 7090 ou le petit 1620 ; ils utilisait principalement des opérations sur les flottants et les tableaux, donc FORTRAN était le langage principal. Leur groupe était SHARE. Pour les applications commerciales, les gens utilisaient le gros 7080 ou le petit 1401 ; ils travaillent sur les décimaux et les chaînes de caractère, ainsi que sur des entrées/sorties améliorées. Ils utilisaient COBOL, et leur groupe était nommé GUIDE. En 1963, il y a eu des changements. Les deux groupes bien distincts étaient en train d’aller l’un vers l’autre : les scientifiques commençaient à rassembler de gros fichiers de données à traiter, qui avait besoin d’entrées/sorties plus efficaces ; les gens des applications commerciales se mirent à l’analyse de régression (i.e. déterminer le lien entre des variables), ce qui utilisait les flottants et les tableaux. Les installations informatiques devraient donc accueillir deux ordinateurs différents, avec leurs langages…

Il fallait donc concevoir un langage capable de faire des opérations sur les flottants et les décimaux, pour des applications scientifiques mais aussi commerciales. Ainsi naquis le concept des IBM System 360. La programmation système et le traitement des listes ne furent pas retenus dans les caractéristiques du nouveau langage. Il devait remplacer FORTRAN, COBOL et LISP, et quelques applications systèmes des langages d’assemblage, sur tous les autres aspects. IBM et SHARE formèrent le Advanced Language Development Committee du projet SHARE FORTRAN en octobre 1963 ; il y eu un sous-comité nommé 3x3, car il avait 3 membres d’IBM et 3 de SHARE. Ce comité se rencontrait trois ou quatre jours par semaine pour concevoir le langage. Le travail fut effectué rapidement, comme pour COBOL ; on le prévoyait sur trois mois. La première version de PL/I, alors nommée FORTRAN VI, était supposée finie en décembre. Le comité fit reporter la date en deux fois, jusqu’à février 1964. Le concept de base était d’en faire une extension pour FORTRAN, en maintenant la compatibilité. Ce but disparu rapidement, de même que le nom FORTRAN VI. Jusqu’en 1965, le langage était connu sous le nom NPL : New Programming Language.

Une première description fut faite au meeting de SHARE en Mars 1964, et un rapport plus complet en avril ; la version à implémenter fut faite en décembre, par le groupe du laboratoire Hursley de IBM en Angleterre. Le nom fut changé en PL/I pour éliminer la confusion avec le National Physic Laboratery d’Angleterre. Si le compilateur avait été développé ailleurs, le nom serait peut-être resté NPL…

PL/I comprenait ce qui était considéré comme les meilleures parts des autres langages : la récursivité et la structure en blocs de ALGOL 60, une compilation séparée avec communications par les données globales comme en FORTRAN, les structures de données et entrées/sorties du COBOL 60. Il y avait également quelques petites nouvelles constructions, résultants de ce mélange. Il apporta aussi des nouveautés :

- programmation concurrente, avec plusieurs tâches créées par un programme - détecter et gérer 23 types d’exception ou d’erreurs à l’exécution - on peut désactiver la possibilité d’utiliser les procédures de façon récursive, pour produire un code plus

performant dans le cas où on est en itératif - les pointeurs sont un type de données, on peut référencer des parties de tableau

Page 32: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 32

IX. Deux langages dynamiques : APL et SNOBOL APL et SNOBOL n’étaient basés sur aucun langage précédent, et n’ont eu qu’une très faible influence sur la conception de langages ultérieurs. Le langage J est basé sur APL, et ICON est basé sur SNOBOL. Ces langages partagent deux caractéristiques : typage et allocation mémoire dynamique. Les variables sont essentiellement non typées : elles prennent un type seulement quand on leur affecte une valeur, et on leur réserve une place mémoire à ce moment là (il était impossible de le faire avant car on ne pouvait pas savoir la taille des données à stocker). APL fut conçu vers 1960 par Kenneth E. Iverson de chez IBM, pour décrire l’architecture des ordinateurs. Le langage fut décrit dans le livre dont il tient son nom : A programming language. Au milieu des années 60, la première implémentation fut développée à IBM. Le langage a de nombreux opérateurs puissants, ce qui pose un problème pour l’implémentation. APL permet de manipuler des tableaux comme s’il s’agissait de scalaires : le transposé d’une matrice nécessite un seul opérateur. On a donc une puissance d’expressivité, mais aussi des programmes durs à lire… On voyait des programmes ou fonctions qui tenaient alors en une seule ligne de combinaisons ! SNOBOL fut conçu par D. J. Farber, R. E. Grisworld et F. P. Polensky des laboratoires Bell pour le traitement des textes. Le cœur de SNOBOL est un ensemble d’opérations puissantes pour la recherche de motifs ; une des premières applications du langage était la conception d’éditeurs de texte. Comme SNOBOL est dynamique, cela le rend plus lent que d’autres langages et il n’est donc plus utilisé pour cela.

X. Vers une abstraction des données : SIMULA 67 Pour avoir des coroutines dans SIMULA 67, la construction de classes a été développée : c’est le début de l’abstraction de données ! L’idée de base de la classe est de rassembler des structures de données avec les fonctions qui les manipulent. Une définition de classe est seulement un modèle [template] pour la structure de données, ce qui est très différent de l’instance d’une classe. Ainsi, un programme peut créer et utiliser plusieurs instances d’une même classe, pouvant contenir des données locales.

Les norvégiens Kristen Nygaard et Ole-Johan Dahl ont développé SIMULA I entre 62 et 64 au centre norvégien d’informatique pour la simulation de systèmes. Il fut implémenté à la fin 1964 sur un ordinateur UNIVAC 1107. A ce moment là, Nygaard et Dahl ont étendus le langage pour qu’il soit utilisable sur des applications au but plus général ; le résultat fut SIMULA 67, présenté en mars 1967. SIMULA 67 est une extension de ALGOL 60, à qui il emprunte la structure de blocs et les instructions de contrôle. Le gros problème de ALGOL et des langages de l’époque pour la simulation était dans le design des sous-programmes : la simulation nécessite que les sous-programmes puissent reprendre à la position où ils ont été arrêté. Un programme avec ce genre de contrôle est nommé coroutines car l’appelant et l’appelé ont une relation d’égalité, plutôt que la relation hiérarchique utilisée dans les langages impératifs.

Page 33: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 33

XI. ALGOL 68 et ses descendants Pascal, C, Modula-2, Oberon, Delphi Le développement de ALGOL ne s’est pas terminé avec le rapport révisé de 1962, même s’il y a eu 6 ans avant l’apparition du suivant, marquant une différence importante. Son premier critère de conception est l’orthogonalité, ce qui entraîne de nombreuses innovations :

- alors que dans les langages ultérieurs, les types de données étaient prédéfinis (peu nombreux en FORTRAN, trop en PL/I), l’utilisateur peut faire les siens en combinant les primitives et les structures de base.

- Des tableaux dynamiques, i.e. dont la déclaration ne précise pas les bornes. Les affectations dans un tel tableau entraînent l’allocation de l’espace requis. On utilise le qualificatif flex, par exemple : flex [1 :0] int list, dit que list est un tableau dynamique d’entiers dont la borne inférieur est 1, mais sans aucune allocation de mémoire. Suivi de l’instruction list := (3, 5, 6, 2), on fait l’allocation pour 4 entiers et les bornes deviennent [1 :4].

De nombreuses fonctionnalités de ALGOL 68 se sont retrouvées dans les langages suivants. Cependant, il a répété certaines erreurs de son prédécesseur, et il a donc été modérément utilisé. Le langage était décrit d’une façon élégante et concise, mais c’était dans un métalangage inconnu ; avant que quelqu’un puisse lire le document, il fallait apprendre ce nouveau métalangage nommé grammaires de van Wijngaarden. Pour rendre la chose encore pire, les concepteurs ont inventé un ensemble de mots visant à expliquer la grammaire et le langage : les mots-clés sont nommés indicants, l’extraction de sous-chaînes devient trimming, et on trouve aussi des choses telles que coercion of deproceduring… La puissance d’écriture de ALGOL 68 provient de son concept d’orthogonalité : peu de primitives, et un usage sans limitation des quelques mécanismes de combinaisons. A l’inverse, PL/I proposait un grand nombre de constructions déjà déterminées… ALGOL 68 a simplement continué dans le style simple, tandis que PL/I rassemblait des particularités de plusieurs langages pour atteindre ses objectifs. Notons quand même que PL/I devait être un outil pour une vaste classe de problèmes, tandis que ALGOL ne s’intéresse qu’aux applications scientifiques. Cependant, malgré tous les avantages de ALGOL, ce fut PL/I qui eut la meilleure audience, en raison des efforts promotionnels de IBM et de la difficulté à comprendre la documentation pour ALGOL… Tous les langages impératifs, même ceux avec de l’orienté objet comme C++ ou Java, doivent certaines de leurs caractéristiques à ALGOL. Prenons le cas de Pascal. Niklaus Wirth était un membre du groupe de travail de la fédération internationale de traitement de l’information (IFIP), créée pour continuer le développement de ALGOL dans le milieu des années 60. En août 1965, il a proposé avec C. A. R. Hoare quelques propositions. Elles furent rejetées par le groupe, comme étant un trop faible progrès sur ALGOL 60 ; à la place on adopta quelque chose de plus complexe, qui devint finalement ALGOL 68. Wirth et quelques membres ne croyaient pas en ce ALGOL 68, en raison de sa complexité et de celle du métalangage servant à le décrire. La version de Wirth et Hoare fut nommée ALGOL-W, implémentée à l’université de Stanford et utilisée par quelques universités comme langage d’apprentissage. Les paramètres étaient passés par valeurs et l’instruction case pouvait faire une sélection multiple. [the value-result method is an alternative to ALGOL 60’s pass-by-name method] L’effort de conception suivant de Wirth, toujours base sur ALGOL 60, fut son grand succès : Pascal. Sa définition parue en 1971, et fut modifiée pendant l’implémentation pour ressortir en 1973. Ses caractéristiques viennent pour bon nombre de langages plus anciens : les types de données définis par l’utilisateur étaient dans ALGOL 68, l’instruction case dans ALGOL-W, et on retrouve les variables structurées de COBOL ou PL/I.

Page 34: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 34

Comme Pascal, C a peu contribué aux autres langages mais a été largement utilisé. Conçu principalement pour la programmation système, il marche également tout à fait pour d’autres champs d’application. Les ancêtres de C comprennent CPL, BCPL, B et ALGOL 68. CPL fut développé à l’université de Cambridge au début des années 60, BCPL était un langage système fait par Martin Richards en 1967. Les premiers travaux sur le système d’exploitation UNIX fut réalisé à la fin des années 1960 par Ken Thompson aux laboratoires Bell. La première version fut écrite en langage d’assemblage. Le premier langage de haut niveau implémenté sous UNIX fut B, qui est basé sur BCPL ; il fut conçu et implémenté par Thompson en 1970. Or BCPL et B sont des langages non typés : toutes les données sont considérées comme des mots machines, ce qui est certes simple mais amène à des complications et des insécurités. Par exemple, il y a un problème si on veut faire une arithmétique des réels au lieu de celles des entiers dans une expression… Dans une implémentation de BCPL, les opérandes d’une opération en flottants étaient précédés d’un point.

Ce problème de typage et quelques autres amenèrent au développement d’un nouveau langage basé sur B, d’abord nommé NB puis C. Il fut développé et implémenté par Dennis Ritchie aux laboratoires Bell en 1972. Le langage fut influencé par ALGOL 68 : on le voit dans ses instructions for et switch, ainsi que dans son traitement des pointeurs. Le seul « standard » pour C pendant quinze ans fut le livre de Kernighan et Ritchie ; le langage évolua lentement, avec des capacités rajoutées par les implémentations. En 1989, l’ANSI produisit un rapport officiel sur C, comprenant de nombreuses choses des implémentations.

Le plus gros impact de Pascal a été sur l’enseignement de la programmation. En 1970, la plupart des étudiants en informatique utilisaient FORTRAN, et quelques universités PL/I ou ALGOL-W. Vers 1975, Pascal était devenu le plus utilisé : il avait été conçu en particulier pour l’enseignement ! Il fallut attendre les années 90 pour qu’il cesse d’être le plus utilisé… Comme Pascal était conçu pour l’enseignement, il lui manque plusieurs choses essentielles pour certaines applications. Par exemple, on ne peut pas écrire un sous-programme prenant en argument un tableau de taille variable. On ne peut pas faire non plus de compilation séparée. Ces manques amènent naturellement des dialectes non standard, comme le Turbo Pascal. La popularité de Pascal repose sur sa simplicité et sa puissance d’expression. C’est un langage assez sûr, surtout comparé à FORTRAN ou à C.

Page 35: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 35

Après Pascal, Niklaus Wirth conçu Modula, qui résultait de ses expérimentations sur la concurrence. Aucun compilateur pour Modula ne fut jamais réalisé, et son développement s’arrêta peu après sa publication. Cependant, Wirth n’a pas abandonné la conception de langages… Son but changea : il voulu construire un langage destiné à être le seul pour un nouveau système nommé Lilith. Tandis que cet ordinateur lui-même ne fut jamais une réussite commerciale, le langage Modula-2 eut un réel succès. La conception de Modula-2 est bien évidemment basée sur Pascal et Modula. Il fournit des modules, ce qui contient le support pour types abstraits de données (les fonctions qui les manipulent comme les types), ainsi que des fonctions de bas niveau pour la programmation système et les coroutines. Le langage fut utilisé pour quelques années dans l’industrie, et principalement autour des années 90 en enseignement. Modula-3 fut conçu conjointement par le centre de recherche de Digital Equipment Corporation à Palo Alto, et le centre de recherche d’Olivetti à Menlo Park, à la fin des années 1980. Il est basé sur Modula-2, Mesa [Mitchell 1979], Cedar [Lampson 1983] et Modula-2+ [Rovner 1986]. Il rajouta les classes et les objets, pour le support de la programmation orientée objet, la gestion d’exceptions, un ramasse-miette, et la gestion de la concurrence. Même s’il est bien conçu et puissant, ses chances d’accéder à un usage répandu sont faibles : la plupart des utilisateurs de Modula-2, sur lesquels on aurait pu s’appuyer, ont quasiment disparu entre temps… Oberon, qui est vaguement basé sur Modula-2, est le dernier né des langages de Niklaus Wirth. Sa dernière version est Oberon-2, de 1993. La passion de Wirth pour la simplicité dans les langages de programmation est une évidence dans Oberon : certaines choses ont été rajoutées à Modula-2, et beaucoup ont été supprimées. Oberon est en contraste tranchant avec C++ et Ada 95 au niveau de la simplicité. Il est rare de trouver un langage nettement plus simple et petit que son prédécesseur… Wirth a rajouté à Modula-2 l’extension de type, qui permet de faire de la programmation orientée objets. Parmi les choses supprimées, on trouve les instructions for et with et de nombreux types (opaques, enumeration, subrage, cardinal). Delphi est un langage hybride, similaire à C++ dans le sens où il a été créée en rajoutant le support de l’orienté-objet à un langage déjà existant, à savoir Pascal. Comme C est un langage puissant mais peu sûr, C++ l’est également dans bien des aspects comme l’arithmétique des pointeurs et la vérification des bornes de tableaux. De même, comme Pascal est plus élégant et sûr que C, Delphi l’est par rapport à C++. Il est également moins complexe : il n’autorise pas la surcharge d’opérateurs ni les classes paramétrées. Delphi, comme Visual C++, fournit une interface graphique (Graphic User Interface). Il fut conçu, soutenu et vendu par Borland, la même compagnie qui développa Turbo Pascal.

Niklaus Wirth, né le 15 février 1934 à Winterthur (Suisse), ingénieur en électronique de l’école polytechnique fédérale, M. Sc. (Laval Canada), Ph. D. (Berkeley). Assistant à l’université de Stanford, professeur à Zurich, en retraite depuis 1999. Reçoit le prix Turing en 1984. A mit au point le PCode, code intermédiaire généré par un compilateur et exécutable sur n’importe quelle machine dotée de l’interpréteur (principe repris par Java).

Page 36: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 36

XII. La programmation logique : PROLOG La programmation logique est l’utilisation d’une notation logique formelle pour communiquer les traitements à calculer. Le calcul des prédicats est la notation utilisée dans les langages de programmation logique actuels. Cette programmation n’est pas procédurale. Les programmes ne disent pas exactement comment un résultat doit être calculé, mais plutôt quelle forme il prendra. Pour qu’un langage dispose de ceci, il faut qu’il dispose de l’information et d’un processus inférant permettant de calculer les résultats. Le calcul des prédicats permet de fournir une forme basique de communiquer avec l’ordinateur, et la méthode de preuve nommée ‘résolution’ (développée par Robinson en 1965) fournie la technique d’inférence. Au début des années 70, Alain Colmerauer et Philippe Roussel dans le groupe d’intelligence artificielle à l’Université d’Aix-Marseille ont développé le concept de Prolog, aidés par Robert Kowalski d’Edinburgh. Les composants basiques de Prolog sont une méthode pour spécifier les propositions dans le calcul des prédicats, et une implémentation d’une forme restreinte de résolution. Le premier interpréteur fut développé à Marseille en 1972. Prolog consiste en une petite collection de déclarations, qui peuvent être assez complexes. Un usage courant est fait pour les bases de données ‘intelligentes’ ; il y a deux déclarations : les faits et les règles. Par exemple, des déclarations de faits : mother(joanne, jake). father(vern, joanne). qui dit que de joanne est la mère de jake, et vern le père de joanne. Une déclaration de règle est alors : grandparent(X, Z) :- parent(X, Y), parent(Y, Z). ce qui dit « on peut déduire que X est le grand parent de Z s’il est parent de Y et que Y est parent de Z ». Une base de données Prolog peut-être interrogée directement avec des déclarations de ‘but’, par exemple father(bob, darcie) va demander si bob est bien le père de darcie. Quand il y a une telle demande, ou but, le système Prolog utilise sa méthode de résolution avant de déterminer la véracité de la déclaration ; il répond alors par true ou false. Prolog est entièrement basé sur les clauses de Horn, qui sont les propositions du type :

(p ^ q ^ … ^ t) → u soit non-p v non-q v … v non-t v u Les clauses de Horn forment un sous-ensemble des formes normales conjonctions dans lesquelles un seul terme est positif. La dénomination « clause de Horn » vient de nom du logicien Alfred Horn qui, le premier, mit en évidence l'intérêt de telles clauses en 1951, dans l'article « On sentences which are true of direct unions of algebras » du Journal of Symbolic Logic, 16, 14-21.

La programmation logique n’est pas extrêmement utilisée. Comme de nombreuses autres approches qui ne sont pas impératives, elle est peu rapide. De plus, les champs d’applications sont restreints : certains systèmes de gestion des bases de données, et quelques parties de l’intelligence artificielle.

Page 37: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 37

XIII. Le plus grand effort de conception de l’histoire : Ada Le langage Ada est le résultat de la plus coûteuse conception de langage jamais entreprise. Il fut développé pour le département de la défense. En 1974, la moitié des applications des ordinateurs de la défense étaient les systèmes embarqués (où le matériel informatique est embarqué avec le périphérique qu’il contrôle). Les coûts logiciels montèrent rapidement, principalement à cause de la complexité croissante des systèmes : plus de 450 langages étaient utilisés, et aucun n’était standardisé par la défense ! Chaque entrepreneur pouvait définir un nouveau langage pour son contrat… A cause de cette prolifération des langages, les applications étaient difficilement réutilisables. De plus, aucun logiciel de développement ne fut créée, puisqu’ils sont dépendants d’un langage. Pour toutes ces raisons, l’armée, la marine et l’Air Force, proposèrent chacun de façon indépendante le développement d’un langage de haut niveau pour ses systèmes embarqué. Malcolm Currie, directeur du département d’ingénierie et recherche à la Défense, forma en 1975 le High-Order Langage Working Group (HOLWG), commandé au départ par le lieutenant-colonel William Whitaker de la Air Force. Le HOLWG avait des représentants de tous les services militaires, ainsi que des liaisons avec l’Angleterre, la France, et l’Allemagne de l’ouest. En avril 1975, le HOLWG produisit le document Strawman, énonçant les particularités requises par le nouveau langage. Il fut suivi par le Woodenman et le Tinman (1976, David Fisher). En janvier 1977, on arriva au Ironman, équivalent en contenu et juste un peu différent au niveau du format… Il fut utilisé comme base pour un appel d’offre, ce qui fait de Ada le premier langage conçu par contrats compétitifs. En juillet 1977, quatre des sociétés (Softech, SRI International, Cii Honeywell / Bull, Intermetrics) furent choisir pour produire de façon indépendante et parallèle ; c’était la Phase 1 de la conception du langage. Les quatre conceptions résultantes étaient toutes basées sur Pascal. En juin 1978, le document des pré-requis passa à Steelman. A la fin de la phase II, le design retenu fut celui de Cii Honeywell / Bull, qui était la seule équipe étrangère (française menée par Jean Ichbiah). Jack Cooper, de la marine, recommanda le nom de Ada pour le langage, qui fut adopté ; Augusta Ada Byron (1815-51), comtesse de Lovelace, mathématicienne et fille du poète Lord Byron, est généralement reconnue comme étant le premier programmeur. Elle travailla avec Charles Babbage sur ses ordinateurs mécaniques, écrivant des programmes pour des processus de calculs. Le design fut publié par ACM et distribué à un lectorat de 10 000 personnes. Une conférence d’évaluation fut organisée en octobre 1979 à Boston, avec des représentants d’une centaine d’organisations européennes et des Etats-Unis. Sur les 500 rapports reçus de 15 pays, la plupart ne suggéraient que des modifications minimes. On passa à la nouvelle version du document, Stoneman, en février 1980. Une version révisée de la conception fut complétée en juillet 1980 et accepté comme MIL-STD 1815, le standard Ada Language Reference Manual. Le 1815 vient de l’année de naissance de la comtesse. Une autre version fut faite en juillet 1982. L’ANSI a standardisé Ada en 1983. Le design du langage Ada fut alors gelé pour au moins cinq années. Du langage Ada, on peut retenir les 4 caractéristiques suivantes :

- packages. On encapsule les objets de données, les spécifications des types et les procédures. Ca permet d’avoir une abstraction de données quand on conçoit le programme.

- Gestion des exceptions/erreurs. - Généricité. On peut écrire une procédure de tri qui utilise un type de données non spécifié.

La procédure devra juste être liée au type concerné avant exécution. L’instruction qui fait la liaison demande au compilateur de générer une version de la procédure avec le type de donnée choisit. On nomme ceci des generic units.

- Exécution concurrente d’unité particulière de programme nommée tâches : tasks. La méthode de synchronisation et de communication entre les tâches est nommée rendezvous.

Page 38: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 38

Ada 95 fournit également le polymorphisme en faisant une liaison dynamique entre l’appel d’un sous-programme et sa définition. Le mécanisme de rendezvous fournissait seulement des moyens assez lourds de partager des données entre des processus concurrents. Il fallait introduire une nouvelle tâche permettant de contrôler l’accès aux données partagées : les objets protégés de Ada 95 proposent une alternative. La donnée partagée est encapsulée dans une structure contrôlant tous les accès, aussi bien par rendezvous que par des appels aux sous-programmes.

Dix ans après, on constatait que Ada 95 était employé dans les technologies de pointe : automobile française, transports ferroviaires (TGV, Corail), technologies aéronautiques (Thales Avionics) et spaciales (Alcatel Space, Centre National d’Etudes Spaciales, Arianespace). En 2000, l’Ada Conformity Assessment Authority publia un ensemble de petites corrections accumulées au cours des cinq années précédentes : le Technical Corrigendum 1.

Notons que le langage Ada incarne la plupart des conceptions du génie logiciel et de la conception de langage des années 70. Bien que peu l’aient réalisé au départ, le développement du compilateur pour Ada fut difficile ; il fallu quatre ans pour voir apparaître les premiers compilateurs assez fiables. Ada est un langage assez large, ce qui peut comme toujours le rendre complexe. Hoare a déclaré en 1981 qu’il ne devrait pas être utilisé pour une application où la fiabilité est le point critique, même si c’est précisément le type d’application pour lequel il a été conçu ! En 1988, le Ada Joint Program Office établit le projet Ada 9x pour une révision. Il avait 3 phases : déterminer les besoins de la révision, faire sa définition, opérer la transition. Les besoins du nouvel Ada étaient surtout sur 4 critères : interfaces graphiques, support pour la programmation orientée objets, des librairies plus flexibles, meilleurs mécanismes de contrôle pour les données partagées. La nouvelle version fut nommée Ada 95. La dérivation de type est étendue et offre l’héritage, un ingrédient clé des langages de programmation orientée objets.

Jean Ichbiah, membre de l’Académie des Sciences. Il quitta CII Honeywell / Bull pour fonder Alsys et Textware (logiciels pour PDA et tablet PC’s).

Page 39: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 39

XIV. La programmation orientée objet : Smalltalk La programmation orientée objet a trois grandes caractéristiques : l’abstraction de données, l’héritage et la liaison dynamique. L’héritage [inheritance] apparu de façon limité dans SIMULA 67, dont les classes peuvent être définies de façon hiérarchique. Le concept d’orienté objet vient de l’idée que les programmes simulent le monde réel, et comme le monde est peuplé d’objets, alors sa simulation doit comprendre des objets. En fait, un langage basé sur l’idée de simulation du monde a simplement besoin d’objets qui peuvent envoyer des messages et réagir à ceux qu’ils reçoivent ; en ce sens, on peut construire des objets en Scheme (en utilisant les fermetures). La programmation orientée objet résout les problèmes en identifiant les objets du problème et les traitement qui les utilise. Il ne reste alors qu’à simuler ces objets, leurs processus et les interactions. Le concept qui amena au développement de Smalltalk vient de la thèse d’Alan Kay, à la fin des années 1960 à l’université d’Utah. Kay a envisagé l’avenir de l’informatique, en tombant très juste : des ordinateurs puissants de bureau deviendraient disponible (alors que le premier ne fut pas vendu avant le milieu des années 1970). Il pensait que ces ordinateurs seraient utilisés par des non-programmeurs, et qu’il y aurait donc besoin d’interactions puissantes. Les ordinateurs de son époque étaient orientés sur les commandes, et utilisés exclusivement par des programmeurs professionnels et des scientifiques. Pour un usage non professionnel, Kay pensa qu’un ordinateur devrait être réellement interactif et donc utiliser une interface avec des graphiques sophistiqués. Certains de ces concepts graphiques viennent de l’expérience LOGO par Seymour Papert, où les graphiques aidaient les enfants à utiliser les ordinateurs. Kay envisagea d’abord un système qu’il nomma Dynabook, basé en parti sur le langage Flex, lui-même héritier de SIMULA 67. Dynabook était basé sur le paradigme du bureau type, sur lequel il y a un certain nombre de papiers, certains couverts ; le haut de la pile est souvent le centre d’attention, avec les autres temporairement hors champ. L’affichage de Dynabook aurait matérialisé cette scène : l’utilisateur interagirait avec cet affichage par le clavier et en touchant l’écran avec ses doigts (ndlr : fait en 2006…). Kay est allé au centre de recherches de Xerox, à Palo Alto, et a présenté ses idées sur le Dynabook. Il fut embauché, et cela fit naître le Learning Research Group, dont le premier but était de concevoir un langage pouvant supporter le paradigme de programmation de Kay, avant de l’implémenter sur le meilleur ordinateur personnel disponible. Ces efforts aboutirent à un premier Dynabook, utilisant le matériel Xerox Alto et le logiciel Smalltalk-72 ; de nombreux projets de recherche furent conduit avec ce système, comme plusieurs expérimentations visant à apprendre la programmation aux enfants. Il y eut également d’autres développements, amenant à une séquence de langage qui s’est terminée par Smalltalk-80. Alors que le langage grandissait, il en fut de même avec la puissance de la machine où il se trouvait ; en 1980, aussi bien la machine que le langage avait presque remplie le but d’Alan Kay. L’unité dans Smalltalk est l’objet : ce sont des structures qui contiennent des données locales et un ensemble d’opérations, nommées méthodes, qui peuvent s’appliquer à d’autres objets. Une méthode décrit la réaction d’un objet quand il reçoit le message correspondant. Les constantes numériques comme les systèmes complexes sont tous des objets en Smalltalk. Tous les calculs sont fait de la même façon : envoyer un message à un objet afin d’invoquer une de ses méthodes ; la réponse à un message est nécessairement un objet, qui retourne l’information désirée ou informe simplement que le processus demandé a bien été effectué. La différence entre un message et à un appel à un sous-programme est la suivante : un message est envoyé à un objet de donnée, qui est alors exécuté par le code associé à l’objet ; un appel à un sous-programme envoie la donnée pour qu’elle soit calculer par une unité de code. Du point de vue de la simulation, Smalltalk est la simulation d’un ensemble d’ordinateurs qui communiqueraient entre eux. Chaque objet stocke des données et fournit la possibilité de la manipuler ; de plus, ils peuvent envoyer des recevoir des messa ges. C’est bien là tout ce que fait un ordinateur : stocker et manipuler des données, et communiquer !

Page 40: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 40

Dans Smalltalk, les abstractions pour les objets sont les classes, très similaires à celles de SIMULA 67. Les instances des classes peuvent être créées et sont alors les objets du programme. Chaque objet a ses données locales et représente une instance différente de sa classe. La seule différence entre deux objets de la même classe est l’état de leurs variables locales. Il y a une hiérarchie des classes, comme dans SIMULA 67. Des sous classes héritent des fonctionnalités et variables locales de sa classe parent, ou superclass. Les sous classes peuvent ajouter des variables et fonctionnalités, voire modifier ou cacher certaines choses héritées.

Notons que Smalltalk n’est pas seulement un langage mais aussi un environnement de développement logiciel complet ! L’interface est vraiment graphique, utilisant plusieurs fenêtres, des pop-up et la souris. Les systèmes fenêtrés qui sont maintenant la méthode dominante de faire des interfaces est venue de Smalltalk. Actuellement, la méthodologie la plus importante pour le développement logiciel est celle de l’orienté objet. Bien que l’origine de certaines idées vienne de SIMULA 67, elles ont été portés à maturité par Smalltalk. En ce sens, l’impact de Smalltalk sur le monde informatique est important et durable…

Alan Kay rejoint au début des années 1980 la firme Atari où il sera directeur scientifique, puis en 1984 la société Apple Computer. À l'heure actuelle il travaille pour Hewlett Packard. Il a reçu en 2004 le prix Turing de l'ACM pour ses travaux sur la programmation orientée objet, ainsi que le prix Kyoto.

Page 41: Histoire des langages de programmation - aqualonne.free.fraqualonne.free.fr/Teaching/csc/story.pdf · Histoire des langages de programmation 3 Juin – Août 2006 Avant-Pro pos Considérations

Histoire des langages de programmation Juin – Août 2006 41

XV. Une combinaison d’impératif et d’orienté objet : C++ et Eiffel La première étape de C à C++ a été faite par Bjarne Stroustrup aux laboratoires Bell en 1980. Les modifications comprenaient une vérification du typage pour les fonctions, et surtout des classes. On avait également des classes dérivées, un accès publique ou privé aux composants hérités, des fonctions de destructeur et constructeur, et des classes amies. En 1981, on rajouta la surcharge pour l’opérateur d’affectation. Le résultat fut nommé C with classes et se trouve décrit dans l’ouvrage de Stroustrup. Le premier but était d’avoir l’organisation des programmes de SIMULA 67, soit les classes et l’héritage. Un autre but était que cela ne devrait pas faire baisser les performances, qui sont celles de C. Le C with classes devrait donc être utilisable pour n’importe quelle application où C l’était. Aucune des choses qui rendent le C peu sûr ne fut supprimée ; par exemple, la vérification de l’index lorsqu’on utilise un tableau ne fut même pas envisagée car une sérieuse baisse de performance par rapport à C en aurait résulté… En 1984, le langage fut étendu avec les fonctions virtuelles, la surcharge d’opérateur et de nom de fonctions ; le résultat fut nommé C++. En 1985, la première implémentation nommée Cfront fit son apparition : elle traduisait des programmes C++ en C. Suite aux réactions des utilisateurs, le langage continua d’évoluer : l’héritage multiple vit son apparition (une classe ayant plus d’une classe parente), ainsi que les classes abstraites. La troisième version vit l’apparition des templates, qui fournissent une gestion des exceptions. En 2006, on ajouta également le traitement du λ-calcul. C++ fournit un ensemble de classes prédéfinies, avec la possibilité pour l’utilisateur de faire les siennes. Les définitions de classe stipulent les données objets (data members) et les fonctions (member functions). L’utilisateur peut créer un opérateur, même s’il existe déjà, pour gérer ses propres types de données. De même, il peut y avoir une surcharge des fonctions : plusieurs fonctions avec le même nom, tant que le nombre ou le type de leurs paramètres est différent. Cela permet par exemple de faire un alias avec des paramètres par défaut, qui s’adressera à la fonction générique. La rapidité de C++ en fit devenir un langage très populaire ; il dispose de bons et peu coûteux compilateurs. Il est presque intégralement compatible avec le C : les programmes C peuvent être, pour la plupart, compilés comme des programmes C++. Dans la plupart des implémentations, il est possible de lier du code C++ avec du C. D’un autre côté, comme C++ est un gros et complexe langage, il souffre de problèmes similaires à ceux de PL/I. Il a hérité des insécurités de C, ce qui le rend bien moins sûr que Java ou Ada. Il est davantage une collection d’idées réunies qu’un plan global de conception… Eiffel est un autre langage hybride avec des composantes impératives et orienté objet. Il fut construit par une seule personne : Bertrand Meyer, français vivant en californie. Le langage supporte les types de données abstrait, l’héritage et la liaison dynamique : il supporte donc complètement l’orienté objet. Sa particularité est l’usage des assertions, pour créer une sorte de contrat entre les sous-programmes et ceux qui les appellent. C’est une idée née dans le Plankalkül mais ignorée par tous les langages jusque là ! Eiffel est plus petit et simple que C++, avec une puissance d’expression et une lisibilité assez similaire. C++ était la façon la plus facile pour les compagnies de passer à la programmation orientée objet, puisque leurs programmes connaissaient déjà C. Eiffel n’a pas bénéficié d’un tel chemin d’adoption, ce qui explique qu’il soit plus marginal que C++. De plus, le compilateur Cfront était gratuit et bon marché, tandis que les compilateurs Eiffel étaient plus difficiles à obtenir et surtout plus chers… Enfin, C++ avait le soutien du prestigieux laboratoire Bell tandis que Eiffel sortait de la petite compagnie logicielle de Bertrand Meyer, Interactive Software Engineering.