Bon en fait j'ai la flemme de lire tout ça en détail (surtout que cette histoire de types intersection vs union est très casse-gueule, selon le côté duquel on le regarde et selon la façon dont on définit l'application d'une fonction à une valeur ça peut vouloir dire tout et son contraire...)
Grosso modo, les trois critiques que j'avais envie de faire :
[ul][li]pas de surcharge : supposons que j'ai un operator+ : int -> int -> int, et que je veux définir une lib de calcul flottant, sans avoir une syntaxe complètement incongrue : j'aimerais bien pouvoir redéfinir cette opérateur pour pouvoir
considérer aussi operator+
comme myfloat -> myfloat -> myfloat (pour éviter les pbs intersection/union : suivant le contexte, operator+ pourra prendre l'une de ces deux valeurs). Accessoirement, j'ai envie que cette surcharge se fasse sans que j'ai connaissance des surcharges actuellement définies par operator+ : je veux pouvoir utiliser deux libs qui font ce type de conversion simultanément.
[li]pas de conversion automatique : ma lib de calcul flottant aimerait bien pouvoir convertir automatiquement des entiers en flottants (puisqu'il y a injection, et que sémantiquement il n'y a pas vraiment de différence), i.e. je voudrais bien pouvoir faire surcharger une fonction "conversion : float -> int" qui serait appelée automatiquement par le compilo si elle peut aider à transformer une expression avec un type incorrect en expression avec un type correct.
Notez qu'on peut implémenter la surcharge à partir de la conversion automatique : si j'ai une fonction surchargée en int->int->int et float->float->float, je peux dire qu'elle de type T_Overload(int->int->int,float->float->float), et que j'ai une conversion automatique T_Overload(int->int->int,float->float->float) -> int -> int -> int et une conversion automatique T_Overload(int->int->int,float->float->float) -> float -> float -> float
Evidemment, ça doit poser des problèmes de typage pas forcément triviaux.
[li]filtrage très bas niveau : j'ai un gros code qui manipule, disons, des instructions ASM, que j'ai stockées sous la forme d'une liste. Soit la fonction :
let blah tmp = fun
| [] -> format tmp
| (Label l :: r) -> do_stuff (blah tmp r) l
| (instr :: r) -> blah (tmp+length instr) r
Si, une fois que j'ai écrite 30 fonctions du style, j'ai envie de modifier ma structure de données pour utiliser une liste doublement chaînée (parce que, par exemple, une optimisation a besoin de supprimer une instruction à un endroit quelconque dans le code), je l'ai vraiment DMC (je serais obligé d'écrire :
let blah tmp lst =
if dl_list_empty lst then
format tmp
else
match dl_hd lst with
| Label l -> do_stuff (blah tmp (dl_tl lst)) l
| instr -> blah (tmp+length instr) (dl_tl lst)
ce qui vous en conviendrez est bien plus compliqué et, surtout, très différent : une légère modification de structure de donnée nécessite de modifier tout le code : on se croirait en train de programmer en asm

)
Le problème, c'est que le matching se fait uniquement sur la structure (donc c'est très bas niveau), alors que l'idéal serait de matcher sur des prédicats. On peut imaginer qu'on peut définir des fonctions "reconnaisseur" qui sont l'équivalent des constructeurs, mais en sens inverse. Par exemple on pourrait écrire l'exemple initial de cette manière :
let blah tmp = fun
| Iterator.empty -> format tmp
| (Iterator.hdtl (Label l) :: r) -> do_stuff (blah tmp r) l
| (Iterator.hdtl instr :: r) -> blah (tmp+length instr) r
Avec par exemple :
let Recognizer.Iterator.empty my_list =
if list_empty my_list then
()
else
raise Unrecognized_Pattern
ou encore
let Recognizer.Iterator.hdtl my_list =
try
(hd my_list, tl my_list)
with
_ -> raise Unrecognized_Pattern
Avec la surcharge (

), on pourrait ainsi définir un filtrage bien plus puissant que l'actuel, et surtout bien plus propre...[/ul]
Bien entendu, je n'ai pas encore vraiment réfléchi à comment tout ça se typerait, donc ce n'est peut-être pas forcément réalisable tel quel (peut-être serait on obligé de faire une restriction à la surcharge pour n'accepter les surcharges que si le type du premier argument est différent : je pense que c'est implémenté dans OCaml [plusieurs méthodes peuvent avoir le même nom], mais est-ce qu'on peut aussi faire ça pour des opérateurs comme en C++ ?)
Mais si c'était possible de faire ces 3 choses, OCaml serait certainement largement plus utilisable, et même probablement agréable à utiliser (un filtrage flexible serait vraiment excellent

)