Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generation d'exceptions #3441

Closed
vicuna opened this issue Jul 18, 2002 · 3 comments
Closed

Generation d'exceptions #3441

vicuna opened this issue Jul 18, 2002 · 3 comments

Comments

@vicuna
Copy link

vicuna commented Jul 18, 2002

Original bug ID: 1248
Reporter: administrator
Status: closed (set by @xavierleroy on 2013-08-31T10:46:08Z)
Resolution: suspended
Priority: normal
Severity: feature
Category: ~DO NOT USE (was: OCaml general)
Has duplicate: #4531
Monitored by: @glondu

Bug description

Suite à un thread sur comp.lang.ml (cf ah6vmf$12ik$1@nef.ens.fr) ...

La session suivante illustre quelques problèmes avec la génération
d'exception lors de l'évaluation de structures:

module F(X:sig type t end) = struct exception E of X.t end;;

module F : functor (X : sig type t end) -> sig exception E of X.t end

module B = F(struct type t = bool end);;

module B : sig exception E of bool end

B.E true;;

  • : exn = F(X).E 1

    Le toplevel croit faussement que l'argument de B.E est de type int ....
    Le X dans l'affichage est surprenant.

De même:

module X = struct type t = A | B end;;

module X : sig type t = A | B end

module FX = F(X);;

module FX : sig exception E of X.t end

FX.E X.A;;

  • : exn = F(X).E 0

    Enfin, ça ne serait qu'un problème d'affichage. Mais ce qui
    suit est plus troublant:

FX.E X.B = B.E true;;

  • : bool = true

Donc OCaml compare des valeurs de type différent, et répond même "true" !
On s'attend à ce que les exceptions aient un comportement
génératif; mais non:

let f () = let module E = struct exception E end in E.E;;

val f : unit -> exn =

f () = f ();;

  • : bool = true

Je dirais que cette réponse est incorrecte (en tout cas, incohérente
avec le filtrage dans un gestionnaire d'exception, qui distinguerait
bien ces deux exceptions).

Tout ça avec OCaml 3.04 et 3.04+15 (2002-06-18).

-- Alain

@vicuna
Copy link
Author

vicuna commented Jul 19, 2002

Comment author: administrator

Bonjour Alain,

Suite à un thread sur comp.lang.ml (cf ah6vmf$12ik$1@nef.ens.fr) ...

La session suivante illustre quelques problèmes avec la génération
d'exception lors de l'évaluation de structures:

module F(X:sig type t end) = struct exception E of X.t end;;

module F : functor (X : sig type t end) -> sig exception E of X.t end

module B = F(struct type t = bool end);;

module B : sig exception E of bool end

B.E true;;

  • : exn = F(X).E 1

    Le toplevel croit faussement que l'argument de B.E est de type int ....
    Le X dans l'affichage est surprenant.

De même:

module X = struct type t = A | B end;;

module X : sig type t = A | B end

module FX = F(X);;

module FX : sig exception E of X.t end

FX.E X.A;;

  • : exn = F(X).E 0

    Enfin, ça ne serait qu'un problème d'affichage.

C'est en effet un problème d'affichage. L'identité d'une référence
est représentée par une référence vers une chaîne de caractère.
L'égalité physique entre ces références est ce qui définit la
"générativité" des exceptions, et sert à implémenter le filtrage sur
les exceptions. Malheureusement, l'adresse d'une référence, c'est pas
terrible pour l'affichage. Le compilateur essaye de mettre dans la
chaîne de caractère des infos utiles pour imprimer l'exception, en
l'occurrence un chemin d'accès à la définition de la référence:

exception E of int ---> "E"
module X = struct exception E of bool end ---> "X.E"
ton foncteur ci-dessus ---> "F(X).E"

Bien sûr, le cas du foncteur n'est pas très intéressant car une fois
le foncteur appliqué, l'argument ne s'appellera pas X. Mais le but
est juste d'aider l'utilisateur à localiser la définition de
l'exception lorsque il se prend un message "Uncaught exception". On
pourrait mettre "F().E" à la place, ou "F.E", ou...

Maintenant, quid de l'affichage d'une valeur de type "exn" au
toplevel. Le gros problème est de retrouver le type de l'argument
éventuel de l'exception. C'est en général impossible, car on peut
être entièrement sorti du "scope" de la définition de l'exception.

Cependant, le toplevel fait un "best effort" (le brave garçon): il
essaye de résoudre le chemin trouvé dans le nom de l'exception et
regarde s'il s'évalue en le même identifiant d'exception (la même
référence) que celui trouvé dans la valeur d'exception. Si oui, c'est
gagné, on a retrouvé le type de l'argument et on peut afficher
correctement.

Si non, on fait un deuxième "best effort" qui consiste à afficher la
valeur de l'argument sans infos de types statiques, juste en
s'appuyant sur les tags runtime. Ça marche bien pour les chaînes de
caractères, et très mal pour les entiers/booléens/constructeurs
constants, comme ton exemple le montre...

Je vois que ces "best efforts" entraînent une certaine confusion chez
des utilisateurs rigoureux dans ton genre :-) Je veux bien en
enlever, ça supprimera du code pas très joli dans le toplevel, mais
attention à ne pas sacrifier sur l'autel de la pureté idéologique tous
les hints qui pourraient aider l'utilisateur à comprendre d'où vient
cette fichue exception non rattrapée.

Mais ce qui suit est plus troublant:

FX.E X.B = B.E true;;

  • : bool = true

Donc OCaml compare des valeurs de type différent, et répond même "true" !

C'est un glitch de plus dans l'égalité générique: les "string ref" qui
encodent l'identité des exceptions sont comparées par contenu et non
par adresse... C'est très gênant en effet car si ces string ref ne
sont pas ==, les restes des blocs exception ne sont pas forcément du
même type et ne devraient pas être comparés...

On s'attend à ce que les exceptions aient un comportement
génératif; mais non:

Pas d'accord: le filtrage sur les exceptions (match ou try...with)
implémente exactement le comportement génératif attendu. Refais tes
tests proprement avec des "match" et tout ira bien.

  • Xavier

@vicuna
Copy link
Author

vicuna commented Jul 20, 2002

Comment author: administrator

On Fri, 19 Jul 2002, Xavier Leroy wrote:

C'est en effet un problème d'affichage. L'identité d'une référence
est représentée par une référence vers une chaîne de caractère.
L'égalité physique entre ces références est ce qui définit la
"générativité" des exceptions, et sert à implémenter le filtrage sur
les exceptions.

C'est un peu surprenant, car le filtrage correspond plutôt à une égalité
(=), mais ce n'est pas bien grave.

Je vois que ces "best efforts" entraînent une certaine confusion chez
des utilisateurs rigoureux dans ton genre :-) Je veux bien en
enlever, ça supprimera du code pas très joli dans le toplevel, mais
attention à ne pas sacrifier sur l'autel de la pureté idéologique tous
les hints qui pourraient aider l'utilisateur à comprendre d'où vient
cette fichue exception non rattrapée.

Oui, ça se défend ...

Mais ce qui suit est plus troublant:

FX.E X.B = B.E true;;

  • : bool = true

Donc OCaml compare des valeurs de type différent, et répond même "true" !

C'est un glitch de plus dans l'égalité générique: les "string ref" qui
encodent l'identité des exceptions sont comparées par contenu et non
par adresse... C'est très gênant en effet car si ces string ref ne
sont pas ==, les restes des blocs exception ne sont pas forcément du
même type et ne devraient pas être comparés...

Il serait possible d'imposer pour les exceptions que ces strings ref
soient bien == pour avoir égalité (soit avec un tag runtime spécifique
pour les exceptions, soit en utilisant une valeur particulière x [allouée
une fois pour toute] et en codant les identités par un couple (x,nom);
lorsque la comparaison générique rencontre x dans un bloc, elle passe en
mode "égalité physique"). Je ne sais pas si ça en vaut la peine, bien sûr.

On s'attend à ce que les exceptions aient un comportement
génératif; mais non:

Pas d'accord: le filtrage sur les exceptions (match ou try...with)
implémente exactement le comportement génératif attendu. Refais tes
tests proprement avec des "match" et tout ira bien.

Ok, mais on ne peut pas toujours utiliser le filtrage, par exemple si
l'exception à rattraper n'est pas connue statiquement. Bon, c'est un peu
tiré par les cheveux, mais:

let expect_exn exn f x =
try f x; false
with e when e = exn -> true

ne fait pas ce que l'on veut (ce genre de fonction pourrait être utilisé
pour faire des tests de regression, par exemple).

-- Alain

@vicuna
Copy link
Author

vicuna commented Jan 25, 2012

Comment author: @damiendoligez

Allocating a runtime tag just for this problem: out of question.
Adding a special case for comparison: I don't think the problem is big enough to warrant such a solution.

Another possibility would be to wrap the exception string in an object because objects are never compared structurally. But how much existing C code would be broken by that change?

I'm setting this to resolved/suspended (waiting for someone to come up with a good solution and a patch).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant