Bonjour avec prénom en majuscules, date et heure

Le programme doit afficher Bonjour sur l'écran, demander un prénom. Il affiche ensuite sur la ligne suivante la date et l'heure puis écrit "au revoir" suivi du nom de la personne en majuscules. De façon plus précise, on essaiera de respecter l'initiale majuscule du mot Bonjour, on affichera de la façon la plus simple, en utilisant si possible une chaine de caractères. Le programme affichera si possible "Quel est votre prénom ?" sur la même ligne que le mot Bonjour ; le curseur restera un espace après le signe ? pour la saisie du prénom. Une fois la réponse de l'utilisateur entrée, la date et l'heure seront écrites avec le message de fin sur la même ligne. S'il n'est pas simple de présenter la date sous forme lisible, on pourra laisser la date avec indication du mois sous forme numérique compacte (1 pour Janvier, 2 pour février etc.).

Exemple d'exécution :

si monsieur TEST lance le programme à 11h30:12 le 12/01/1992,
voici ce qui apparait à l'écran :
Bonjour. Quel est votre prénom ? Test
Le 12 janvier 1992 à 11:30 ; au revoir, TEST.
L'algorithme correspondant ne présente aucune difficulté. Il fait référence aux fonctions date, heure et maju. On aurait pu écrire date() et heure() au lieu de date et heure, MCRIRE au lieu de MECRIRE (qui signifie, rappelons "écrire sur la même ligne sans passer à la ligne suivante") pour garder autant de lettres que dans le mot ECRIRE, mais cela est peut-être trop technique. Nous avons préféré la forme simple suivante
* Algorithme de  BONJOUR
ECRIRE  " Bonjour "
MECRIRE " Quel est votre prénom ? "
LIRE pren
ECRIRE "Le ",date," à ",heure," au revoir, ",maju(pren)
La solution Rexx peut rester sous forme de "source", car il n'y a pas de compilation en Rexx ; la précompilation ajouterait 1k au bout du fichier. L'option E dans date signife format Européen (car Rexx dispose d'une dizaine d'options pour afficher l'heure). On notera la différence entre say et call charout qui affichent avec ou sans passage à la ligne suivante. L'instruction pull, qui est une abréviation et une adaptation de parse upper pull traduit automatiquement en majuscules.
/* BONJOUR.REX */
  call charout , "Bonjour. Quel est votre nom ? "
  pull pren
  say "le" date(E) "à" time() "au revoir," pren
La fonction date qui possède de nombreuses options ne permet pas toutefois d'obtenir les mois en lettres. Pour passer des nombres aux lettres, plusieurs méthodes sont possibles. La plus simple consiste à utiliser une structure des cas, la seconde à indexer les noms de mois dans une structure (tableau, phrase etc.) ; nous présentons ici les deux solutions. La première utilise la structure de cas
Aux cas où
  cas moi =  1
     mois <-- 'Janvier'
  cas moi =  2
     mois <-- 'Février'     etc.
  cas moi = 12
     mois <-- 'Décembre'
  autres cas
     mois <-- ""
     écrire "numéro de mois invalide"
Fin des Cas
Une fois traduite en Rexx, cette structure de cas résoud le probléme avec la première solution :
parse value date(E) with jr '/' moi '/' an
 select
  when moi =  1  then mois = 'Janvier'
  when moi =  2  then mois = 'Février'
  when moi =  3  then mois = 'Mars'
etc.
  when moi = 11  then mois = 'Novembre'
  when moi = 12  then mois = 'Décembre'
end
Une solution plus concise et plus élégante consiste à définir une phrase dont les mots sont les noms des mois ; la deuxième solution Rexx est alors
NomDesMois = 'Janvier Février Mars Avril Mai Juin Juillet Août'
NomDesMois = NomDesMois 'Septembre Octobre Novembre Décembre'
parse value date(E) with jr '/' moi '/' an
mois = word(NomDesMois,moi)
Le programme Turbo Pascal correspondant est nettement plus long : il n'existe pas de primitive donnant l'heure ou la date et la fonction upper ne travaille que sur un caractère à la fois. Contrairement au problème de Comar, toutes les instructions sont écrites dans le programme principal, sans aucune fonction ni procédure.
program BONJOUR_en_PASCAL ;

	uses	dos 	;				(* pour Date et Heure *)
	var	pren			: string   ; 	(* contient le prénom   *)
		ic 			: integer ;	(* indice de boucle     *)
		an,mois,jour,js		: word	; 	
		moisc,jourc		: string	;  	(* équivalents caractères *)
		heur,mini,sec,cent 	: word	;
		heurc,minic		: string	; 	(* équivalents caractères *)

BEGIN (* bonjour_en_pascal *)

  (* demande du prénom *)
  writeln('Bonjour ') ;
  write('Quel est votre nom ? ') ;
  readln(pren) ;

  (* passage en majuscule de chacune des lettres de PREN *)
  for ic := 1 to length(pren) do begin
       pren[ic] := upcase(pren[ic])
   end ; (* fin pour IC *)

  (* on récupère la date grâce à l'unité Dos *)
   GetDate(an,mois,jour,js) ;
   GetTime( heur,mini,sec,cent ) ;

  (* 	conversion en caractère : il faut éventuellement rajouter 0 pour avoir
      	un cadrage homogène sur 2 caractères *)
  str(jour,jourc)	;  if jour  < 10 then jourc  := '0' + jourc  ;
  str(mois,moisc)	;  if mois < 10 then moisc := '0' + moisc ;
  str(heur,heurc)	;  if heur < 10 then heurc  := '0' + heurc  ;
  str(mini,minic)	;  if mini < 10 then minic  := '0' + minic  ;

  (* affichage final*)
  writeln('Le ', jourc,'/',moisc, '/', an, ' à ', heurc,':',minic, ' au revoir, ',pren)

END. (* bonjour_en_pascal *)
Toutefois, avec les bonnes procédures dans le fichier inclus Bonjour.Ins, (à savoir jour, mois, an, heure, minute et maju) on aurait pu réaliser un programme beaucoup plus proche de l'algorithme et de toutes façons beaucoup plus lisible. Un modèle possible d'un tel programme en Turbo Pascal (version 5 ou supérieure) pourrait être le suivant. On appréciera le fait qu'une seule variable est visible globalement (pren), qui est la seule à figurer explicitement dans l'énoncé.
PROGRAM BONJOUR_en_PASCAL ;

   uses 	dos  ; 			(* pour Date et Heure 	*)
   (*$I 	Bonjour.Ins 						*)
    Var 	pren  : string   ;	(* contient le prénom   	*)

BEGIN (* bonjour_en_pascal *)
  writeln('Bonjour ') ;
  write('Quel est votre nom ? ') ;
  readln(pren) ;
  writeln('Le ',jour,'/',mois,'/',an,' à ',heure,':',minute,' au revoir, ',maju(pren) )
END. (* bonjour_en_pascal *)
En Pascal, pour afficher le nom du mois plutôt que son numéro, on peut aussi utiliser un tableau constant de chaînes de caractères grâce à la déclaration suivante
const tab : array[1..12] of string[10] =  ('Janvier','Février','Mars','Avril','Mai',
   'Juin',Juillet','Août','Septembre','Octobre','Novembre','Décembre')
on accède alors au nom du mois grâce à l'expression TableauMois[ mois ]. En Awk, les fonctions date et heure n'existent pas. Toutefois, ctime() renvoie la date et l'heure dans un format particulier que l'on réarrange très facilement avec les variables $i. Le deuxième mot de ctime() est en effet le numéro du mois, le troisième mot correspond au jour dans le mois etc.
# BONJOUR.AWK
BEGIN {
  print  "Bonjour "
  printf "Quel est votre nom ? " ;  getline pren < "CON"
  $0    = ctime()
  date  = $3 " " $2 " " $NF
  heure = substr($4,1,5)
  print "le " date " à " heure " au revoir," toupper(pren)
} # fin du programme ; pas de parcours de fichier ni de section END
A priori, pour utiliser cette solution AWK, il faut, à l'exécution, donner le nom d'un fichier de données car un programme AWK travaille en standard avec toujours au moins un fichier de données. On peut lever cette restriction à condition de rajouter en début de programme l'instruction ARGV[1] = "", ou même ARGV="" si la version de Awk le permet mais cela n'a vraiment que peu de rapports avec notre algorithme. Cette instruction a pour but de mettre à vide la variable ARGV qui contient les arguments passés au programme, c'est-à-dire traditionnellement une ou plusieurs spécifications (peut être ambigue) de fichiers. Une version unix du meme programme est peut differente :
# BONJOUR.AWK

BEGIN { ARGV[1] = ""
        print  "Bonjour " ; printf "Quel est votre nom ? "
      }

{ pren = $0
  "date " | getline
  date  = $3 " " $2 " " $NF ; heure = substr($4,1,5)
  print "Le " date " à " heure " au revoir, " toupper(pren)
  exit
}
Pour obtenir en Awk le nom du mois en toutes lettres, on peut utiliser la même technique qu'en Rexx :
NomDesMois = "Janvier Février Mars Avril Mai Juin Juillet Août"
NomDesMois = NomDesMois "Septembre Octobre Novembre Décembre"
$0 = NomDesMois
# moi est le numéro, mois le nom
mois = $moi
La solution Dbase ressemble fortement à la solution algorithmique. On notera la contraction du Mcrire et du Lire en une seule demande via ACCEPT. Cette contraction est délicate : ce qu'on a le droit de mettre après ACCEPT n'est pas exactement ce qu'on peut mettre après un ? ou un SAY. Ainsi, ? A, B+C où A, B et C sont des chaînes de caractères est correct (la distinction entre l'affichage conjoint B, C et l'affichage de la concaténation B+C est subtile) mais ACCEPT A,B+C TO ... est incorrect. La fonction upper en Dbase travaille sur des chaînes. Dbase ayant été bien francisé (même si il reste certaines questions en français auxquelles il faut répondre par Y ou N dans la version Dbase3plus), upper("é") renvoie bien "E", contrairement au Pascal qui renvoie "é" dans ce cas. On retrouve ce problème quand on trie des mots avec des caractères accentués. Si le tri utilise l'ordre ascii, alors mille sera placé avant médecin, d'où un tri pour le moins surprenant !
* BONJOUR en DBASE
     ? " Bonjour "
     ACCEPT "Quel est votre nom ? " to pren
     ? "Le ",date()," à ",time()," au revoir, ",upper(pren)
En C, on retrouve un programme similaire au Pascal. Cette-fois ci, on dispose de fonctions dans des bibliothèques standards, auxquelles on accède par les instructions #include. La lecture et l'écriture en C peuvent être formatées (ou seulement typées), par exemple comme ici avec le spécificateur de format %s (ce que rappelle le f de printf et scanf). Ce formatage peut donner lieu à des conversions surprenantes. L'entête permet d'utiliser les fonctions des bibliothèques standard pour les entrées, les chaînes et le temps :
/* Bonjour en Turbo C */
#include 
#include 
#include 
Le reste du programme utilise les fonctions en bibliothèque :
main() { char pren[80] ; struct tm *now ; long nbsec ;
 printf("Bonjour\n");
 printf("Quel est votre prénom ? ");
 scanf("%s",pren)  ;  strupr(pren) ;
 time(&nbsec) ; now = localtime(&nbsec) ;
 printf("le %02d/%02d/%02d à %02d:%02d au revoir, %s",
     w->tm_mday, now->tm_mon, now->tm_year,
     now->tm_hour,now->tm_min, pren) ;
} /* fin du programme principal */
La solution en Apl est relativement courte aussi :
[0]	BONJOUR ; MSG ; PREN
[1]	„ Exemple classique d'E/S et de conversion sur chaîne
[2]	` C	MSG C 'Bonjour. Quel est votre prénom ?'
[3]	PREN	 C `
[4]	PREN	C (‘ MSG) {CARSPECIAUX 70 \f "Lucida Bright Math Symbol"}PREN
[5]	DATE , ' - au revoir,' , (MAJU PREN) , '.'
où la fonction MAJU est définie par :
[0]	Z	 	C	MAJU X ; VS ; NBX
[1]	„ Passage en majuscule de X
[2]	LETTRES	C	{CARSPECIAUX 127 \f "Lucida Bright Math Symbol"}AV[ (62+VS),89+VSC26]
[3]	NBX		C	LETTRES {CARSPECIAUX 105 \f "Symbol"} X
[4]	Z		C	LETTRES[NBX - 26 x NBX > 26 ]
Quelques explications s'imposent : Z C dans la ligne zéro c'est-à-dire dans l'en-tête de la fonction MAJU signifie que le résultat est explicite et donc renvoyé. X est le paramètre de la focntion. Les variables VS et NBX sont locales ; par contre LETTRES est globale. boiteAV est le vecteur atomique ; il représente l'ensemble des caractères. LETTRES contient ici les majuscules de A à Z puis les minuscules de a à z. NBX contient les codes correspondant aux lettres du paramètre X. La ligne 3 vient retirer aux codes des lettres minuscules la valeur 26 de façon à ce que l'indexation dans LETTRES redonne les majuscules. De même, la fonction DATE est ({CARSPECIAUX 127 \f "Lucida Bright Math Symbol"}TS est un vecteur système qui contient le mois, le jour etc. sous forme numérique)
[0]	Z		{CARSPECIAUX 67 \f "Lucida Bright Math Symbol"}	DATE ; JOUR ; NUMMOIS ; CHMOIS ; AN
[1]	JOUR		{CARSPECIAUX 67 \f "Lucida Bright Math Symbol"}	{CARSPECIAUX 127 \f "Lucida Bright Math Symbol"}TS[3]
[2]	NUMMOIS	{CARSPECIAUX 67 \f "Lucida Bright Math Symbol"}	{CARSPECIAUX 127 \f "Lucida Bright Math Symbol"}TS[2]
[3]	AN		{CARSPECIAUX 67 \f "Lucida Bright Math Symbol"}	{CARSPECIAUX 127 \f "Lucida Bright Math Symbol"}TS[1]
[4]	CHMOIS	{CARSPECIAUX 67 \f "Lucida Bright Math Symbol"}	MOIS[NUMMOIS;]
[5]	Z		{CARSPECIAUX 67 \f "Lucida Bright Math Symbol"}	'Le ', (èJOUR) , '   ' , MOIS , '   ' ,èAN
Ces fonctions APL ne font pas à proprement parler partie du programme correspondant à l'exemple. Elles sont seulement présentes en même dans la zone de travail ("WorkSpace"). Apl ne travaille pas seulement comme un langage mais aussi comme un environnement. La solution en Turbo Prolog définit aussi plusieurs prédicats (mois et hello) regroupés dans une même application. Le choix du prédicat mois et de la variable Mois est volontairement ambigu. On appréciera la lisibilité et la facilité de remplacement du numéro de mois par son équivalent chaîne de caractères grâce à l'unification. Pour ceux qui ne connaissent pas Turbo Prolog, rappelons que upper_lower(x,y) a trois niveaux d'utilisation :
- si x est donné et y libre, alors y est lié à l'équivalent minuscule de x
- si x est libre et y donné, alors x est lié à l'équivalent majuscule de y
- si x et y sont donnés, upper_lower renvoie vrai si x et y sont égaux, sans
  distinction de majuscules ou minuscules ; sinon upper_lower renvoie faux.
Pour correspondre au "typage" de Turbo Prolog, on commence par les "pseudo déclarations"
predicates
   mois(integer,string)
   hello
goal
  hello.
Le programme véritable commence ensuite, précédé de l'instruction "clauses". clauses
 mois(1,"Janvier").
 mois(2,"Février").
 mois(3,"Mars").
 mois(4,"Avril").
 mois(5,"Mai"). /* etc. */
 hello :-
   clearwindow,
   write(" Bonjour. Quel est ton prénom  "),
   readln(Pren),
   upper_lower(PrenMaj,Pren),
   date(An,Mois,Jour),
   mois(Mois,ChMois),
   write("Le ",Jour," ",ChMois," ",An," bonsoir,",PrenMaj)
 . /* fin de hello */
Nous présentons aussi quelques versions simplifiées de Bonjour. La première est en assembleur. En assembleur sous MSDOS, on peut générer de fichiers de type Com ou Exe. Les programmes correspondants sont, une fois assemblés très courts, même si leur texte est long, puisqu'il faut tout détailler. On donne tout d'abord une version ultra-courte qui affiche seulement "Bonjour" par un programme Exe. ; Solution assembleur minimale générant un .EXE (705 octets) ; on affiche seulement "Bonjour" à l'écran DSEG SEGMENT ; en Assembleur, les variables sont MESSAGE DB 'Bonjour$' ; rangées dans un segment à part des DSEG ENDS ; instructions du programme.Le symbole ; $ indique la fin de la chaine. SSEG SEGMENT STACK ; les fichiers de type .EXE imposent DW 80 DUP ( 'GH' ) ; une " pile " SSEG ENDS BONJOUR SEGMENT ; les instructions du programme sont ; aussi à mettre dans un segment. ASSUME CS : BONJOUR, DS : DSEG ; il faut alors indiquer où trouver ; les données, les instructions MAINPP PROC FAR ; le programme principal doit être ; défini comme une procédure DEBUT: PUSH D ; ces lignes initialisent les registres SUB AX, AX ; de façon à bien pointer les segments PUSH AX MOV AX, DSEG MOV DS, AX ; voici l'affichage : on utilise la fonction 9 du DOS (via ; l'interruption 21 après avoir indiqué où commence la chaine ; de caractères. MOV DX, OFFSET MESSAGE MOV AH, 09 INT 21H RET MAINPP ENDP BONJOUR ENDS END DEBUT ; on indique où doit démarrer le programme. Le même affichage avec un .COM est encore plus court, puisqu'il ne fait que 19 octets soit une dizaine d'octets de plus que le mot 'Bonjour'. Sigalons qu'un programme équivalent compilé à partir de Pascal ou C prendrait au moins un ou deux kilo octets ; passer de 19 octets à 2048 octets représente une grande différence de taille.
; Solution  minimale générant un .COM  (19 octets)
       BJR2   SEGMENT
              ASSUME CS:BJR2,DS:BJR2
              ORG  100H
       DEB:   JMP  DEBUT
       MSG    DB   'Bonjour$'
       DEBUT: MOV  DX,OFFSET MSG
              MOV  AH,9
              INT  21H
              RET
       BJR2   ENDS
              END  DEB
Une solution plus complète qui lit le nom et le réaffiche est déjà plus longue en termes de lignes source sans être très lisible ; par exemple, il faut connaitre la notion d'interruption (notamment celle numéro 20), savoir ce qu'est une fonction Dos ou Bios (comme la fonction 9) pour découvrir où se situe la traduction du mot LIRE de l'algorithme.
; Solution détaillée : on dit bonjour, on demande le nom,
; ---------- on dit "au revoir" suivi du nom.
HLO    SEGMENT PARA PUBLIC 'CODE'
       ASSUME CS:HLO,DS:HLO,ES:HLO,SS:HLO
       ORG  100H
DIB:
       JMP  DIBUT
CR     DB   0DH,'$'
LF     DB   0AH,'$'
QRY    DB   'Quel est votre nom ? $'
PREN   DB   8, 10 DUP('$')
FINCH  DB   'Au revoir, $'
DOLAR  DB   '$'
POINT  DB   '.$'

DIBUT:
; demande du nom : on pose la question
       MOV  DX,OFFSET QRY
       MOV  AH,9
       INT  21H

; demande du nom : lecture de la réponse (variable PREN)
       MOV DX,OFFSET PREN
       MOV AH,0AH
       INT 21H
; demande du nom : --> on remplace le caractère Enter par
; Dollar pour utiliser la fonction 9 de l'int 21
       MOV BX,DX
       MOV CX,[BX]+1
       MOV CH,0
       ADD BX,2
       ADD BX,CX
       MOV AL,'$'
       MOV [BX],AL
; demande du nom : on passe à la ligne suivante
       MOV  DX,OFFSET CR
       MOV  AH,9
       INT  21H
       MOV  DX,OFFSET LF
       MOV  AH,9
       INT  21H
; affichage du message de fin
       MOV  DX, OFFSET FINCH
       MOV  AH,9
       INT  21H
; réaffichage de la réponse (variable PREN)
       MOV  CX,4
       MOV  DX,OFFSET PREN
       ADD  DX,2
       MOV  AH,9
       INT  21H
; passage à la ligne suivante
       MOV  DX,OFFSET POINT
       MOV  AH,9
       INT  21H
       MOV  DX,OFFSET CR
       MOV  AH,9
       INT  21H
       MOV  DX,OFFSET LF
       MOV  AH,9
       INT  21H
; retour au dos
       MOV AH,4CH
       INT  21H
HLO    ENDS
       END  DIB ; fin du programme assembleur
Pour les solutions en Lisp, on se méfiera des différents dialectes, surtout au niveau des entrées et des sorties. Ainsi, en AutoLisp (Lisp pour AutoCad) on peut lire des chaînes, des points, des distances, des angles très simplement. La fonction print d'AutoLisp ne renvoie pas la même chose que la fonction print de Lelisp, etc. Setq ne correspond pas vraiment à une affectation mais réalise une liaison qui est en proche, princ écrit une chaîne de caractères sans passer à la ligne, strcat réalise la concaténation, terpri envoie une ligne vide au terminal. De même, en LeLisp, read lit une chaine et renvoie la valeur lue. Un Bonjour simplifié possible en AutoLisp est
(defun C:bonjour() ; Lisp pour Autocad
    (setq pren (getstring " Bonjour.Quel est votre prénom ? "))
    (princ (strcat " Au revoir, " pren  ".")) (terpri)
)
Et en LeLisp
(defun bonjour()
  (print "Bonjour. Quel est votre prénom ? ")
  (setq pren (read) )
  (print "Au revoir, " pren ".")
)
Pour la version simplifiée de bonjour en Cobol : on a utilisé volontairement un branchement via l'instruction PERFORM. Certains raccourcis (l'absence de OF MOIS dans l'instruction MOVE MOIS notamment) sont aussi volontaires.
 IDENTIFICATION DIVISION.
 PROGRAM-ID. BONJOUR.
 AUTHOR. HUNAULT.
 ENVIRONMENT DIVISION.
 DATA DIVISION.
 WORKING-STORAGE SECTION.
 01 REPONSE.
    05 PREN                     PIC X(20).
 77 INDM                        PIC S9(4)    COMP.
 01 LIGNEDATE.
    05 FILLER                   PIC XXXX     VALUE 'Le  '.
    05 JJ                       PIC 99.
    05 FILLER                   PIC XX       VALUE SPACES.
    05 MM                       PIC X(10).
    05 FILLER                   PIC XX       VALUE '19'.
    05 AA                       PIC 99.
 01 TABLEAUMOIS.
    05 LIBEL.
       07 FILLER           PIC X(10)   VALUE    'Janvier   '.
       07 FILLER           PIC X(10)   VALUE    'Février   '.
       07 FILLER           PIC X(10)   VALUE    'Mars      '.
       07 FILLER           PIC X(10)   VALUE    'Avril     '.
       07 FILLER           PIC X(10)   VALUE    'Mai       '.
etc.
    05 ZONEDAT REDEFINES LIBEL.
       07 ELEM OCCURS 12   PIC X(10).
 01 DAT.
    05 AN                       PIC 99.
    05 MOIS                     PIC 99.
    05 JOUR                     PIC 99.
 PROCEDURE DIVISION.
 PROG.
     DISPLAY 'Début'.
     DISPLAY 'Bonjour quel est votre nom ? '.
     ACCEPT PREN.
     PERFORM PROG-JOUR.
     DISPLAY LIGNEDATE ', bonsoir ' PREN.
     STOP RUN.

 PROG-JOUR.
     ACCEPT DAT FROM DATE.
     MOVE AN       OF DAT TO AA IN LIGNEDATE.
     MOVE JOUR  OF DAT TO JJ IN LIGNEDATE.
     MOVE MOIS         TO INDM.
     MOVE ELEM (INDM) TO MM.
Le texte qui suit correspond à un Bonjour en Smalltalk (nous avons utilisé des positionnements curseur de façon à obtenir toujours l'affichage toujours au même endroit, car sinon il dépend de la position de la souris au moment où est lancé le programme)
Bonjour " Exemple de commentaire, lire, écrire et affectation "
  | pren |
  Cursor offset: 140 @ 150.
  pren := Prompter
     prompt: ' Bonjour. Quel est ton prénom ? '
     default: ''.
  pren := ' Merci. Au revoir ' , (pren asUpperCase), ' ' ,
          (Date today) printString.
  Cursor offset: 140 @ 300.
  Menu message: pren.
Un tel programme ne peut s'utiliser seul. Il est en fait considéré comme un sous programme (une méthode) liée à une classe d'objets. Par exemple, nous l'avons associé à un objet de type démonstration. Si DemoUno est une instance d'un tel objet, l'envoi du message DemoUno Bonjour lancera notre "programme". Le stockage du texte du programme ne se fait pas dans un fichier mais dans "l'image" du lanagage Smalltalk (contrairement à Apl, tout le langage est stocké, et non pas seulement les fonctions utilisateur). Signalons au passage que le texte source de toutes les parties de Smalltalk est accessible et modifiable. En ADA , nous définirons une fonction uppercase à l'intérieur d'un "module" et notre programme principal sera une "procédure". Ada sait bien gérer la compilation séparée, sait même dans certains cas utiliser un même code (dit "générique") pour traiter des structures semblables (par exemple des tableaux) dont les éléments sont de même type (tableaux d'entiers et tableaux de chaines, par exemple).
--  Bonjour.Ada
        with text_io ; use text_io ;

procedure bonjour is
    subtype id is string(1..5) ;
    nom : id ;
function  uppercase(chaine : in id ) return id is
      c : character ; i : integer ; ch : id ;
begin -- uppercase
   for i in chaine'range loop	-- ne pas mettre for i in 1..chaine'length
	-- a cause d'un appel uppercas(ch(3..9)) possible
         c := chaine(i) ;  put(c) ;
         if c >= 'a' and c <= 'z'
            then ch(i) := 'M' ;
            else ch(i) := c ;
         end if ;
     end loop ;
     return ch ;
end uppercase ;
begin -- bonjour
    put("Bonjour, quel est votre nom ? (sur 5 carac) ");
    get(nom) ;
    put("Merci. Le  ");
    put(", au revoir, ");     put( uppercase(nom) ) ;
    put_line(".");
end bonjour ;