Tout programme en exécution peut être sujet à des erreurs pour lesquels des stratégies de détection et de réparation sont possibles. Ces erreurs ne sont pas des bugs mais des conditions particulières (ou conditions exceptionnelles, ou exceptions) dans le déroulement normal d'une partie d'un programme.
Par exemple, l'absence d'un fichier utile n'est pas un bug du programme ; par contre, ne pas gérer son absence en serait un.
Quand on n'a pas d'outil pour séparer l'exécution normale et l'exécution exceptionnelle du programme, un algorithme, dont l'exécution normale s'exprime de façon simple et élégante, peut devenir difficile à maintenir une fois « enrobé » par une logique de traitement de ces situations exceptionnelles ; disposer au niveau du langage de programmation de structures pour différencier l'exécution normale de l'exécution dans un contexte exceptionnel peut être utile. Ces structures de contrôles forment un système de gestion d'exceptions.
Exemples d'implémentations :
Dans les années 1950, la mémoire des ordinateurs était onéreuse et les sous-programmes étaient principalement utilisés pour réduire la taille des programmes: un ensemble d'instructions était écrit une fois et pouvait être appelé depuis plusieurs endroits du programme.
Le support des sous-programmes a également permis aux ordinateurs d'implémenter des algorithmes récursifs.
Exemple de sous-programme en basic
10 X = 2 19 FARG = X 20 GOSUB 50 22 Y = FRET 30 PRINT Y 40 END 48 '------------------------------------ 49 ' Double la valeur passée en argument 50 FRET = FARG*2 60 RETURN
Dans cet exemple, à la ligne 20 la valeur courante du compteur ordinal est archivée puis le programme effectue un saut à la ligne 50. Arrivé à la ligne 60, l'instruction RETURN permet de réaffecter la valeur archivée dans le compteur ordinal et donc de revenir à la position d'appel du sous-programme.
Ces structure de contrôles nécessitent donc un automate à pile pour enregistrer l'adresse de retour du sous-programme.
Repose sur la notion de pile, avec deux instructions :
Aujourd'hui les sous-programmes sont utilisés pour améliorer la structuration d'un programme. Repérés par une étiquette de branchement, ils peuvent donc être considérés comme une extension du saut inconditionnel et, du point de vue de la programmation structurée, en partagent la plupart des défauts.
Beaucoup de langages modernes ne supportent donc pas directement la notion de sous-programme au profit de constructions de haut niveau qui peuvent être appelées, d'un langage à l'autre procédure, fonction, méthode, ou routine par exemple. Ces constructions ajoutent la notion de passage de paramètres et surtout le cloisonnement des espaces de nom pour éviter que le sous-programme ait un effet de bord sur la routine appelante.
Il existe diverses extensions à la notion de procédure comme les coroutines, signaux et slots, callback, méthodes virtuelles...
Elles permettent de modifier dynamiquement, c’est-à-dire à l'exécution, la structure du flot d'exécution du programme.
La programmation événementielle est une autre façon de contrôler le flot d'exécutions d'un programme. Il s'agit de créer des gestionnaires qui viendront s'abonner à une boucle mère, chargée d'aiguiller les évènements qui affectent le logiciel.
Cette méthodologie a été popularisée par les bibliothèque de programmation des interfaces utilisateurs. Elle est en effet particulièrement adaptée pour gérer les mouvements de souris par exemple. On retrouve le même principe dans des outils non graphiques comme awk ou XSLT par exemple. A un niveau plus proche du matériel on retrouve une philosophie similaire avec les interruptions.