Sous-programmes Concepts généraux Passage de paramètres Fonctions Sous-programmes en tant que paramètre
Concepts généraux Originalement, les sous-programmes (procédures et fonctions) étaient un mécanisme de réutilisation du code, une façon d’éviter la répétition. Maintenant, on pensent aux sous-programmes comme un mécanisme d’abstraction. Un sous-programme est un bloc nommé (avec une porté locale) qui encapsule un algorithme. Sémantiquement, un sous-programme est une opération complexe qui peut être initiée (appelée) comme si elle était une opération de base. On dénomme ce mécanisme, l’abstraction de processus.
Un sous-programme… est défini au moyen d’opérations de bas niveau, possède un nom, incorpore un moyen d’accepter des paramètres et de retourner des résultats (le passage de paramètres et la communication via des objets non-locales), est exécuté figeant l’unité du programme ayant appelé ce sous-programme, puis en exécutant les instructions du bloc, avant de revenir à l’unité l’ayant appelé.
L’entête d’un sous-programme: nom, mode de passage des paramètres, le type des valeurs retournées (si le sous programme est une fonction). Le corp d’un sous-programme: une séquence d’instructions. Une procédure étend le langage de programmation: elle devient une nouvelle instruction. De façon similaire, une fonction est une nouvelle opération.
Paramètres Un paramètre d’un sous-programme est la généralisation d’un objet manipulé par les instructions du bloc correspondant — un sous- programme devrait fonctionner de la même manière, peu importe la valeur des paramètres. On les appel aussi “dummy variables”. Le passage de paramètres signifie le replacement des entités généralisées dans la déclaration d’un sous-programme (paramètres formels) par des objets concrets.
Passage de Paramètres Le mode de passage de paramètres détermine comment les arguments seront transmis au sous-programme: • la valeur seulement • l’adresse seulement • l’adresse et la valeur et les restrictions sur l’usage de ces arguments: • lecture seulement • écriture seulement • lecture/écriture.
Un modèle simplifié d’une procédure Une procédure est une “boite noire” qui lit des données en entré et /ou écrit des les résultats en sortie. in out in out
Passage par valeur Le Passage par valeur est grandement utilisé: paramètres in d’Ada; paramètres value de Pascal; tout les paramètres de Algol-68, C. Seul la valeur d’un paramètre est donnée au sous- programme. Pour conserver cette valeur, on utilise une variable locale (qui devient l’adresse du paramètre). Ceci est normalement implémenté en copiant la valeur du paramètre dans un espace mémoire appartenant au sous- programme. Ceci peut être coûteux si les paramètres sont des objets de grande taille, comme des tableaux.
Passage par résultat Le passage par résultat est une façon de transmettre les sorties d’un sous programme. En Ada: paramètre out L’adresse (et non la valeur) du paramètre est envoyée au sous-programme — mais en lui donnant accès pour l’écriture seulement (« write-only »). Techniquement, on a un objet local qui ne peut apparaître dans des expressions.
Passage par valeur-résultat En Ada: paramètres in out Appelé aussi passage par copie. Quand le sous-programme est activé, la valeur des paramètres est copiée dans un objet local. Après l’exécution du sous- programme, la valeur finale de cet objet est recopiée dans le paramètre.
Exemple de passage par valeur-résultat -- procedure P(in out X: someType); -- un bloc Q appel P(Z), Z vient de Q begin X := Z; -- le corp de P utilise X Z := X; end; Cette méthode, et le passage par résultat peuvent — dans in certaines situations bizarres — dépendre de l’ordre dans lequel les paramètres sont évalués (voir le manuel).
Passage par référence paramètres var en Pascal; Tout paramètres en Fortran (anciennes versions). L’adresse et la valeur sont toute deux disponible dans les instructions du sous-programme. Ceci est implémenté par l’adresse indirecte: le paramètre est en effet l’adresse d’une variable de l’unité ayant appelée le sous-programme. Aucune copie n’est nécessaire.
Exemple de passage par référence -- procedure P(var X: someType); -- un bloc Q appel P(Z), Z vient de Q begin -- le corp de P utilise Z end; Tout changement de Z à l’intérieur de P est préservé après que P soit terminé, et sera visible dans Q.
Exemple de passage de paramètres: Pascal program P; var J: integer; A: array [1..10] of integer; procedure SWAP( MODE X,Y: integer); var TMP: integer; begin TMP := X; X := Y; Y := TMP; end; begin J := 3; A[J] := 6; SWAP(J, A[J]); write(J, A[3]); end. MODE = in: J = 3, A[3] = 6 (aucun changement) MODE = out: impossible (on ne peut lire la valeur de X) MODE = ref ou in out: J = 6, A[3] = 3
À considérer… Un problème important du passage par référence peut être la dénomination (« aliasing »). Une situation possible: passer la même variable en tant que deux paramètres différent. Une autre possibilité: une variable non-locale à laquelle on fait référence dans le sous-programme qui est également un paramètre. Un paramètre passé par résultat, valeur-résultat ou référence doit être une variable. Comment le passage par référence est-il différent du passage par valeur-résultat?
Prolog est différent La classification des modes de passage de paramètres basé sur les adresses et valeurs est raisonnable pour les langages impératifs ayant des variables pouvant être modifiées. Cependant, elle ne s’applique pas à Prolog, où les adresses ne sont jamais disponibles (en particulier, il n’y a pas d’assignations). append([a], [b], Result) in in out append(First, Second, [a,b]) out out in append([X,b], [c,Y], [a,P,Q,d]) ni in ni out
Fonctions Une fonction produit une valeur, retournée par une instruction spéciale telle que return someValue; ou assignée au nom de la fonction (comme en Pascal). Quand les fonctions sont utilisées dans des expressions, elles enrichissent le langage. On peut les traiter comme des opérateurs. Par exemple, si EXP(X, Y) a été défini pour calculer XY, on peut l’utiliser dans une expression: Z := 2.0 * EXP(A, N); malgré que l’exposant n’était originalement pas défini dans le langage.
Fonctions (2) Les effets secondaires des fonctions sont un problème. Idéalement, seul les paramètres in (et aucun effet secondaire) ne devrait être permis dans une fonction mathématiquement correcte. Si des effets secondaires sont nécessaires, une procédure devrait être utilisée — avec un paramètre réservé pour transmettre la valeur qui aurait été retournée par la fonction. Un choix de conception (concernant l’orthogonalité!): restreindre le type des objets pouvant être retourné par les fonctions.
Sous-programmes en tant que paramètres Le concept est simple: un algorithme qui dépend d’un autre algorithme. Scheme est conçu parfaitement de ce coté; les langages impératifs le sont moins. Considérez l’exemple d’une intégration numérique—trouver l’aire sous la courbe définie par une fonction mathématique.
Sous-programmes en tant que paramètres: Pascal function DEFINITE_INTEGRAL( function F(ARG: real): real; LOW, HIGH: real): real; const N_INTERVALS = 1000; var DELTA, SUM, X: real; I: integer; begin DELTA := (HIGH - LOW) / N_INTERVALS; X := LOW; SUM := F(X); for I := 1 to N_INTERVALS - 1 do X := X + DELTA; SUM := SUM + 2.0 * F(X) end; SUM := SUM + F(X); DEFINITE_INTEGRAL := 0.5 * DELTA * SUM
Sous-programmes en tant que paramètres: Pascal (2) N’importe quel fonction real real peut être passé à cette “méta-fonction”: function SQ( A: real ): real; begin SQ := A * A end; {...} x := DEFINITE_INTEGRAL(SQ, 0.0, 9.0); Cet appel retourne (environs) 243.0.