This commit is contained in:
2026-09-13 10:20:16 +02:00
parent 019c8ad335
commit b72193d656
38 changed files with 1523 additions and 837 deletions

View File

@@ -1,259 +1,159 @@
# Exemples / DO-DON'T — Chapitre 18 — `Result`, erreurs et exceptions
# Exemples / DO-DON'T — Chapitre 18 — `Result`, erreurs, exceptions et faults
> Document compagnon non normatif tant qu'une règle n'est pas explicitement référencée comme normative par le chapitre.
> Document compagnon. Les exemples illustrent les règles du chapitre ; la formulation normative reste dans le chapitre lui-même.
## Exemples actuellement présents dans le chapitre
### Exemple 1
## Hiérarchie
```text
Object
└── Error
├── ResultError
── Exception
── Exception
└── Fault
```
### Exemple 2
```text
public final class ParseError extends ResultError {
}
public final class FileNotFoundException extends Exception {
}
```
### Exemple 3
```text
message: String
cause: Option<Error>
i18nMessage: Option<I18nMessage>
```
### Exemple 4
```text
message
message humain canonique / fallback
cause
erreur causale purement informative
peut contenir un ResultError ou une Exception
n'est pas automatiquement propagée
i18nMessage
clé et paramètres de localisation
ne contient pas un tableau de traductions
```
### Exemple 5
```text
code: ResultErrorCode
```
### Exemple 6
```text
code -> stable, machine-readable, non localisé
message -> humain, canonique / fallback
i18nMessage -> localisation externe
```
### Exemple 7
```text
throw exception;
```
### Exemple 8
```text
Result::Ok(T)
Result::Err(E)
```
### Exemple 9
```text
E doit être ResultError ou un descendant de ResultError
```
### Exemple 10
```text
Result<Data,ResultError>
Result<Data,ParseError>
Result<Void,ResultError>
```
### Exemple 11
```text
Result<Data,Error>
Result<Data,Exception>
Result<Data,FileNotFoundException>
```
### Exemple 12
```text
Result<T>
```
### Exemple 13
```text
Result<T,ResultError>
```
### Exemple 14
```text
return Result::Ok(value);
return Result::Err(error);
```
### Exemple 15
```text
result::expectOk(...)
result::expectErr(...)
```
### Exemple 16
```text
ResultError -> Exception
Exception -> ResultError
```
### Exemple 17
```text
throw ParseException(..., Option::Some(parseError));
```
### Exemple 18
```text
catch (FileNotFoundException error) {
return Result::Err(FileResultError(..., Option::Some(error)));
public final class IndexOutOfBoundsFault extends Fault {
}
```
### Exemple 19
## `ResultError`
DO : utiliser `Result` lorsque l'échec est une valeur normale à inspecter explicitement.
```text
T + throws -> interdit
Result<T,E> -> valide sans throws
Result<T,E> + throws -> valide
```
### Exemple 20
```text
throws IOException
```
### Exemple 21
```text
supprimer entièrement des exceptions déclarées
restreindre une famille à une ou plusieurs sous-familles compatibles
gérer localement tout ou partie des exceptions du contrat parent
```
### Exemple 22
```text
throw FileNotFoundException(...); // valide
throw ParseError(...); // erreur
throw Error(...); // erreur
```
### Exemple 23
```text
catch (IOException error) {
throw error;
func parseExternalInput(String input) -> Result<Value, ParseError> {
...
}
```
### Exemple 24
DON'T : placer une `Exception` ou un `Fault` dans le paramètre erreur de `Result`.
```text
try { ... }
try { ... } finally { ... }
finally { ... }
Result<Value,FileNotFoundException> // ERROR
Result<Value,IndexOutOfBoundsFault> // ERROR
```
### Exemple 25
## `Exception`, `throw` et `throws`
```text
func readConfig(String path) -> Config
throws IOException
{
...
}
```
Un retour direct est compatible avec `throws`.
```text
throw FileNotFoundException(...); // OK
throw IndexOutOfBoundsFault(...); // ERROR
throw ParseError(...); // ERROR
```
## `Fault`, `fault` et `faults`
```text
method elementAt(uint64 index) -> T
faults IndexOutOfBoundsFault
{
if (index >= this::length()) {
fault IndexOutOfBoundsFault(index, this::length());
}
...
}
```
La clause `faults` est optionnelle et non exhaustive.
DO : appeler sans cérémonie lorsque le fault n'est pas un chemin normal à traiter.
```text
T value = list::elementAt(index);
```
DO : capturer explicitement lorsque le programme veut réellement récupérer ce cas.
```text
try {
...
} catch (SpecificException error) {
...
} catch (ParentException error) {
...
} finally {
T value = list::elementAt(index);
} catch (IndexOutOfBoundsFault faultValue) {
...
}
```
### Exemple 26
Aucune propagation de `faults` n'est obligatoire :
```text
catch (FileNotFoundException error) {
...
} catch (IOException error) {
...
func outer() -> Void {
inner(); // inner peut déclarer faults SomeFault
return Void;
}
```
### Exemple 27
## `catch`
Valide :
```text
catch (IOException error) {
...
} catch (FileNotFoundException error) {
}
catch (IteratorInvalidatedFault faultValue) {
...
}
```
### Exemple 28
Invalide :
```text
fin normale du try
fin normale d'un catch
return traversant la construction
throw propagé
break / continue traversant la construction
Exception non capturée par les catch
catch (Error error) // ERROR
catch (ResultError error) // ERROR
```
### Exemple 29
`catch` ne peut cibler que `Exception`, `Fault` ou leurs descendants.
## Direct versus valeur conditionnelle
Accès affirmatif :
```text
return
throw
break
continue
emit
User user = users[id]; // absence -> KeyNotFoundFault
```
### Exemple 30
Absence normale :
```text
index hors limites
division entière par zéro
overflow checked
représentation mémoire invalide
borne dynamique invalide lors d'une construction directe lorsque la règle du type le définit
Option<User> user = users::get(id);
```
## DO / DON'T / WHY / compiler error / edge cases
Le Core ne doit pas créer automatiquement une variante `tryOp()` uniquement pour transporter le même échec dans `Result`.
La couverture structurée de cette section sera enrichie au fur et à mesure de la fermeture des règles du chapitre. La migration `0.2.12` conserve volontairement les exemples historiques dans le chapitre afin de ne perdre aucun contexte normatif.
## Erreur statique versus fault runtime
```text
StaticArray<int32,3> values = [1, 2, 3];
int32 a = values[5]; // ERROR compilation
```
```text
uint64 index = readIndex();
int32 b = values[index]; // peut produire IndexOutOfBoundsFault au runtime
```
Un statement `fault` explicite reste évidemment valide :
```text
if (!state::isValid()) {
fault InvalidStateFault(...);
}
```