v0.2.17
This commit is contained in:
@@ -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(...);
|
||||
}
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user