Bon, j'ai fait quelques tests, parce que le coup de la division par 0 m'intriguait (en fait, j'imagine qu'il y a des points communs avec ce qui se passe pour les accès des tableaux).
Après quelques essais, on se rend compte qu'une instruction comme :
with b = (Int32) (8 / 3),
est refusée par le compilateur. Hé oui, la division renvoie un type Maybe. Il faut gérer explicitement le cas de la division par 0... Comme ça, si un jour 3 devient égal à 0, le code marchera toujours.
with b = (2.1 + 3.2) + 1.3,
Par ailleurs, cette instruction aussi est refusée. Une addition entre deux flottants renvoie un type Maybe. Ah, il faut gérer le cas où il y aurait un overflow ?
Non, puisque :
est autorisé. Mais dans ce cas, comment détecte-t-on un int overflow quand on ajoute deux entiers ?
La solution que j'ai trouvée si on ne veut pas se prendre la tête est toute simple.
1 2 3 4 5 6 7 8 9 10
| define $T
force
(
Maybe($T) x,
) =
if x is
{
failure then alert,
success(n) then n
}. |
(Ensuite, il suffit d'écrire :
with b = (Int32) force(8 / 3),
On se retrouve donc dans le cas de figure habituel. Alert sert en effet à déclancher une exception... non rattrapable !
Un question : est-ce vraiment ce que le concepteur voulait qu'on fasse ? Ou préfère-t-il que l'on gère systématiquement à la main les divisions par 5, dans le cas où 5 vaudrait 0 ?
Bon, je viens de regarder rapidement dans la bibliothèque standard. D'une part, j'ai trouvé une variante de la division qui renvoie un Int32... et qui renvoie 0 en cas de division. Oui, c'est beaucoup plus simple comme ça. Le débuggage doit être beaucoup simple : au lieu d'une exception, on renvoie une valeur sans aucun rapport.
D'autre part, dans la bibliothèque, on trouve la fonction nth qui renvoie le Maybe(n-ième élément d'une liste). Et la fonction force_nth qui renvoie le n-ième élément. Ou fait un alert si la liste est trop courte. On retombe donc ici dans le schéma classique. Sauf que le alert n'est pas rattrapable.
Au final, je ne suis absolument pas convaincu de la sûreté d'Anubis. Je trouve certains choix exagérément contraignants. Et emplacer les exceptions par un plantage direct n'est pas une nouveauté : le C y a pensé avant. Caml (et d'autres langages !) me semble donc un meilleur choix. On peut d'ailleurs définir l'opérateur suivant pour se forcer à gérer les cas douteux :
1 2 3
| let (/?) x y =
if y = 0 then None
else Some (x / y) |
Partager