programmez-en-d/scope.whata

112 lines
4.2 KiB
Plaintext
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[set
title = "Portées ([c scope])"
partAs = chapitre
translator = "Raphaël Jakse"
proofreader = "Stéphane Gouget"
]
Comme nous l'avons vu, les expressions qui doivent toujours être exécutées sont écrites dans le bloc [c finally], et les expressions qui doivent être exécutées quand il y a des conditions d'erreurs sont écrites dans des blocs [c catch].
On peut faire les observations suivantes sur l'utilisation de ces blocs~ :
- [
[c catch] et [c finally] ne peuvent pas être utilisés sans un bloc [c try].
]
- [
Certaines variables dont ces blocs ont besoin peuvent ne pas être accessibles à l'intérieur de ces blocs :
[code=d <<<
void foo(ref int r)
{
try {
int nombreÀAjouter = 42;
r += nombreÀAjouter;
peutLever();
} catch (Exception exc) {
r -= nombreÀAjouter; // ERREUR de compilation
}
}
>>>]
Cette fonction modifie le paramètre référence puis annule cette modification quand une exception est levée. Malheureusement, [c nombreÀAjouter] n'est accessible que dans le bloc [c try], là où il est défini.
[p Note~ : | ceci renvoie à la notion d'espace de noms~ ; comme pour la notion de durée de vie des objets, cela sera expliqué dans un chapitre ultérieur.]
]
- Écrire toutes les expressions potentiellement sans rapport dans un seul bloc [c finally] en bas sépare ces expressions du code auquel elles sont liées.
Les instructions [c scope] ont la même fonctionnalité que les blocs [c catch] et [c finally] mais sont meilleures sur beaucoup d'aspects. Les trois instructions [c scope] décrivent des expressions qui devraient être exécutées lorsque qu'on quitte des portées~ :
- [c scope(exit)]~ : l'expression est toujours exécutée lorsqu'on quite la portée, que ce soit normalement ou à cause d'une exception~ ;
- [c scope(success)]~ : l'expression n'est exécutée que si l'on quitte la portée normalement~ ;
- [c scope(failure)]~ : l'expression n'est exécutée que si l'on quitte la portée à cause d'une exception.
Même si ces instructions sont proches du mécanisme des exceptions, elles peuvent être utilisées sans bloc [c try-catch].
Comme exemple, ré-écrivons la fonction précédente avec une instruction [c scope(failure)]~ :
[code=d <<<
void foo(ref int r)
{
int nombreÀAjouter = 42;
r += nombreÀAjouter;
scope(failure) r -= nombreÀAjouter;
peutLever();
}
>>>]
L'instruction [c scope(failure)] assure que l'expression [c r -= nombreÀAjouter] sera exécutée si on sort de la portée de la fonction à cause d'une exception. Un avantage de [c scope(failure)] est le fait que l'expression qui annule l'autre expression est écrite à côté de celle-ci.
Les instructions [c scope] peuvent aussi être utilisées par blocs~ :
[code=d <<<
scope(exit) {
// ... expressions ...
}
>>>]
Voici une autre fonction qui teste ces trois instructions~ :
[code=d <<<
void test()
{
scope(exit) writeln("en quittant 1");
scope(success) {
writeln("si succès 1");
writeln("si succès 2");
}
scope(failure) writeln("si levée 1");
scope(exit) writeln("en quittant 2");
scope(failure) writeln("si levée 2");
leveLaMoitieDuTemps();
}
>>>]
Si aucune exception n'est levée, la sortie de la fonction n'inclut que les expressions [c scope(exit)] et [c scope(success)]~ :
[output <<<
en quittant 2
si succès 1
si succès 2
en quittant 1
>>>]
Si une exception est levée, la sortie inclut les expressions [c scope(exit)] et [c scope(failure)]~ :
[output <<<
si levée 2
en quittant 2
si levée 1
en quittant 1
object.Exception@...: le message d'erreur
>>>]
Comme on peut le constater, les blocs des instructions [c scope] sont exécutés dans l'ordre inverse de celui dans lequel ils sont écrits dans le programme. C'est parce que du code situé plus bas peut dépendre de variables qui le précèdent. Exécuter les instructions [c scope] dans l'ordre inverse permet d'annuler les effets de bords d'expressions précédentes dans un ordre cohérent.