Typage fort et downcast : j'enrage !!!
Par -Alexandre LEGOUT aka LAlex- le vendredi, novembre 14 2003, 12:21 - AS2 - Lien permanent
Je n'arrive pas à trouver un moyen de faire du cast, tout en continuant à utiliser le typage fort de MX 2004 ... :? En fait, une simple utilisation du constructeur permet de ne pas provoquer d'erreur de compilation, mais au lieu de faire un downcast, cela me renvoie null ... ![]()
Pour ceux qui ne connaissent pas le terme "downcast", ca correspond à changer le type d'un instance vers une classe qui hérite de sa classe actuelle. Cette classe est en fait située "plus bas" dans la chaîne d'héritage, et le cast est la conversion d'un type à un autre, d'où le terme de downcast ...
Par exemple, une voiture est un véhicule, mais un véhicule n'est pas forcément une voiture. Si on a une instance d'un véhicule et qu'on la caste vers la classe voiture, on va downcaster cette instance ... Un cast dans l'autre sens (de voiture vers véhicule) est un upcast, et il est le plus souvent effectué de manière implicite ...
Revenons à ce que je disais :// classe Parent
class Parent {
function Parent() {
}
function doIt() {
trace("doIt");
}
function toString():String {
return "Parent instance";
}
}
// classe Child
class Child extends Parent {
function Child() {
super();
}
function doItChild(test:Child) {
trace(">> doItChild");
trace(test);
}
function toString():String {
return "Child instance";
}
}
/********** Utilisation **********/
var par : Parent = new Parent();
trace(par); // Parent instance
var chi : Child = new Child();
chi.doItChild(Child(par));
// >> doItChild
// null
Je ne vois pas dans ce cas la ce qui pourrait empêcher le downcast, mais apparemment ca lui pose un problème ... 8| Décidemment, ce typage fort pose plus de problèmes qu'il n'en résout ... :? D'ailleurs, vous devez commencer à me trouver lourd avec ca car je n'ose pas compter combien de posts j'ai fait sur ce sujet !!!
Mais la je me retrouve encore une fois à buter la dessus, et ca me fais enrager une fois de plus !!! :?
Commentaires
Hello


moi en ce moment mon problème au niveau du typage fort etc.. c'est au niveau des with, l'utilisation des with en AS2 est beaucoup plus lourde qu'en AS1 je trouve
bye
Salut Lalex,
Le compilateur devrait t'envoyer une erreur car ton downcast est illegal. Tu ne peux pas prendre une instance d'une superclass et le transformer en une instance d'une subclass, c'est impossible. Tu peux faire un cast explicite seulement si ta variable contient deja une instance de la bonne classe mais, soit elle a ete upcastee a un moment donne et tu veux que le compilateur se "rappelle" que c'est bien une instance de ta classe pour faire quelques operations, soit tu veux restipuler la classe au cas ou elle a ete "perdue", dans le cas ou l'instance a ete placee dans un tableau par exemple.
Le downcast en soi n'est pas legal en POO, ce qui est legal, c'est seulement le cast explicite vers une classe dont la variable est deja une instance.
Par exemple ce qui marche, c'est ca:
var par : Parent = new Child(); // <- difference est icitrace(par); // Child instance
var chi : Child = new Child();
chi.doItChild(Child(par));
// >> doItChild
// Child instance
En Java, ton code aurait renvoye une erreur "Type mismtach" a la compilation parce que "par" n'est pas une instance de la classe Child et le cast est donc illegal. Si tu avais utilise un tableau, ou disons un vector ou une list en java, alors tu aurais eu une exception pendant le run time, toujours type mismatch. Conclusion: le compilateur Flash est nul, il devrait carrement detecter ce type d'erreur, et le run time nous donne zero information sur le probleme :(.
Je pense que ca vaudrait le coup que au moins le test player ait une gestion des run time error.
Timoth'
Fut' aurais-je mal compris alors ? 8|
Donc, si j'ai bien suivi, il faut que l'instance ait été à un moment une instance de la classe vers laquelle on veut caster ?
Donc je ne peut pas caster vers Child à partir d'une instance de Parent c'est ca ?
Je cerne mieux maintenant, merci Timoth'!
Décidemment, heureusement que tu es la pour éclairer ma lanterne aussi souvent ! 
Oui, ou que l'instance soit d'une class subclasse de la classe vers laquelle tu veux caster. En fait, si on veut chippoter, je crois qu'on ne pas vraiment dire "ait été", parce qu'un objet est toujours une instance de la classe a partir de laquelle il a ete construit. Ce qui peut changer c'est juste le type de la variable qui reference cet objet.
Exactement
Par exemple, si tu as une instance de Parent, le compilateur ne te laissera pas appeler une methode de Child dessus (normal). Si tu sais qu'en fait cette variable de type Parent contient en fait une instance de Child, il faut que tu informes le compilateur avant d'appeler ta methode. Apres le compilateur, te dira: "OK Lalex, je te fait confiance, tu me dit que cette variable contient une instance de Child alors je te laisse appeler une methode de Child dessus". Sauf que si ta variable ne contient pas une instance de Child, ca foire pendant le run-time.
Donc avec ca, c'est normal que tu puisses toujours UPcaster puisque toutes les methodes et proprietes de la superClasse sont disponibles a partir d'une instance de subClass et le compilateur te laisse faire. Pour un downcast ou un caste explicite, par contre, il faut que tu saches exactement ce que tu fais et le compilateur va juste te faire confiance "aveuglement".
Je viens de faire le test en java et j'ai dit une connerie: le compilateur ne voit pas l'erreur non plus a la compilation. En fait c'est normal maintenant que j'y pense, il nous fait vraiment confiance :p. Par contre au run time j'ai bien:
En fait je trouve que c'est la syntaxe en AS2 qui est trompeuse. telle que c'est, on fait
var o:ClassPourLeCast = ClassPourLeCast(variableDUneAutreClasse);on dirait que le constructeur est appele pour modifier l'instance. Meme dans le bytecode l'appel de fonction est la :?. En Java, la syntaxe pour le cast est differente d'un appel de methode et rend cette notion de non-modification visible immediatement:ClassPourLeCast o = (ClassPourLeCast)variableDUneAutreClasse;Je suis desole de toujours faire des comparaisons avec Java mais c'est le seul autre language que je connaisse raisonnablement bien :p.
A+
Timoth'
En fait, le problème c'est comme je le disais dans un autre commentaire, le constructeur d'une classe reste une fonction en prototype-based ... 8|
Sinon, le typage d'une variable (virtuel, car il n'existe que pour le compilo) correspondrait a pointer à un certain endroit de la chaîne de prototypes donc ... et le cast déplacerait ce pseudo-pointeur ...
Sinon, Java est un bon point de comparaison pour le comportement que devrait avoir l'AS2, mais dans la pratique, c'est deja plus délicat ... 8|
Et voila, j'ai encore dit une bêtise sur mon blog !
Ce n'est ni la première ni la dernière fois, mais je suis content parce que en plus de me faire comprendre certaines subtilités, ca introduit le dialogue !!!
Donc, merci encore (j'espère que ceux qui s'y connaissent moins lisent les commentaires ;))
Salut,
Oops, j'ai dit une deuxieme betise aussi :P. Je viens de jeter un coup d'oeil au bytecode avec flasm 1.5 et la fonction n'est pas appelee lors du cast, a la place il y a bien une instruction Cast. Dans un vieux test que j'avais fait avec flasm 1.5 alpha, il m'avait semble avoir vu un appel de fonction, j'avais du me planter...
Quoi qu'il en soit, ca montre que le cast n'est bien qu'un simple test qui n'affecte pas l'instance et que c'est bien la syntaxe AS2 qui porte a confusion. Je me demande d'ailleurs si ca peut arriver que le compilateur se trompe et compile un appel de fonction au lieu d'un cast?? J'imagine que ca a du etre bien etudie quand meme pour pas que ca foire (enfin j'espere).
En tout cas, maintenant que la doc swf est sortie, je copie le morceau sur l'instruction Cast pour reference ici. Ca explique le null, que tu avais en sortie dans ton script d'origine:
1 Pops the ScriptObject to cast off the stack.
2 Pops the constructor function off the stack.
3 Determines if object is an instance of constructor (doing the same comparison as ActionInstanceOf).
4 If the object is an instance of constructor, the popped ScriptObject is pushed onto the stack. If the object is not an instance of constructor, a null value is pushed onto the stack.
Timoth'
Fil des commentaires de ce billet