Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Utilisation des interfaces et sûreté du typage

9 réponses
Avatar
Patrice
Bonjour à tous,

J'ai une question dont j'ai presqe honte après qques années de dev. dotnet.
Quid de l'utilisation des interface et du typage statique ?
Naïvement, j'étais persuadé que le compilateur vérifiait statiquement
l'implémentation d'une interface par un objet lors de la sollicitation de
cette interface sur cet objet.

Exemple : disons que C1 est une classe n'implémentant pas une interface I.

il semble que ce code soit valide :

dim V1 as I
dim V2 as C1
V1=V2

ou encore :

V1=Ctype(V2, I)
Or on est statiquement certain que ce cast ne marche pas il me semble.

So ??? Tout est permi vraiment ??

9 réponses

Avatar
Fred
Dans : news:,
Patrice écrivait :
Bonjour à tous,



Bonjour,

J'ai une question dont j'ai presqe honte après qques années de dev.
dotnet. Quid de l'utilisation des interface et du typage statique ?
Naïvement, j'étais persuadé que le compilateur vérifiait statiquement
l'implémentation d'une interface par un objet lors de la
sollicitation de cette interface sur cet objet.

Exemple : disons que C1 est une classe n'implémentant pas une
interface I.
il semble que ce code soit valide :

dim V1 as I
dim V2 as C1
V1=V2

ou encore :

V1=Ctype(V2, I)
Or on est statiquement certain que ce cast ne marche pas il me semble.



So ??? Tout est permi vraiment ??



Je dirais que tout ce qui n'est pas certain (mais pas impossible !) est
compilé pour une affectation en late binding, non ?
On peut très bien écrire :

Dim o as Object = ÇaRetourneUnObjet()
o.ExecuteUneMéthode

Même si l'intellisense ne nous aide pas en l'occurrence, et pour cause,
le compilateur l'accepte.
Avec les risques d'erreur que cela implique au runtime. Erreurs qui sont
détectées à la compilation en early binding.

Cela répond-il (au moins partiellement) à ta question ?

--
Fred
http://www.cerber mail.com/?3kA6ftaCvT (enlever l'espace)
Avatar
Patrice
"Fred" wrote in message
news:

Je dirais que tout ce qui n'est pas certain (mais pas impossible !) est
compilé pour une affectation en late binding, non ?
On peut très bien écrire :

Dim o as Object = ÇaRetourneUnObjet()
o.ExecuteUneMéthode

Même si l'intellisense ne nous aide pas en l'occurrence, et pour cause, le
compilateur l'accepte.



Cela répond-il (au moins partiellement) à ta question ?



Salut Fred.
Merci pour cette réponse mais à vrai dire, non, pas tout à fait.
Dans l'exemple que tu prends, on ne peut raisonnablement rien attendre de
mieux du compilateur, puisqu'on ne lui fournit aucune info.
En revanche, dans les deux miens, le compilateur sait que :
1) que V2 est de type C1 (et non object)
2) que C1 n'implémente pas I
3) que C1 ne fournit aucun cast spécifique vers I

A partir de là, je pense qu'il dispose de toutes les informations
nécessaires pour interdire le cast et refuser de compiler.

D'où mon entêtement, non d'une pipe, pourquoi est-ce possible ?? :)

A+
Avatar
Fred
Dans : news:,
Patrice disait :
"Fred" wrote in message
news:

Je dirais que tout ce qui n'est pas certain (mais pas impossible !)
est compilé pour une affectation en late binding, non ?
On peut très bien écrire :

Dim o as Object = ÇaRetourneUnObjet()
o.ExecuteUneMéthode

Même si l'intellisense ne nous aide pas en l'occurrence, et pour
cause, le compilateur l'accepte.



Cela répond-il (au moins partiellement) à ta question ?



Salut Fred.
Merci pour cette réponse mais à vrai dire, non, pas tout à fait.
Dans l'exemple que tu prends, on ne peut raisonnablement rien
attendre de mieux du compilateur, puisqu'on ne lui fournit aucune
info. En revanche, dans les deux miens, le compilateur sait que :
1) que V2 est de type C1 (et non object)
2) que C1 n'implémente pas I
3) que C1 ne fournit aucun cast spécifique vers I

A partir de là, je pense qu'il dispose de toutes les informations
nécessaires pour interdire le cast et refuser de compiler.

D'où mon entêtement, non d'une pipe, pourquoi est-ce possible ?? :)



C'est bien ce que j'ai compris, enfin, je crois :-). Le compilateur,
dans ton exemple, ne sait pas que V2 n'implémente pas I, même si toi, tu
le sais !
Donc il va générer du late binding. Et comme la variable V1 est juste
déclarée comme implémentant une interface, elle peut être de n'importe
quel type (comme mon object). Pourquoi alors interdire l'affectation à
la compilation ?
Je pense même qu'on peut trouver un autre cas : imagine que V2, qui est
de type C1, soit en fait une instance d'une classe dérivée de C1, disons
C3, qui elle, implémenterait l'interface I ! (je n'ai pas testé si cette
construction est possible, mais j'en suis quasiment persuadé)
Le fait qu'une classe n'implémente pas explicitement une interface
n'interdit pas le fait qu'une instance de cette classe puisse tout de
même l'implémenter. Je le vois comme un cas particulier de mon exemple
(Mon objet n'implémente pas une interface qui contiendrait la méthode
«ExecuteUneMéthode»). Pour que le compilateur n'accepte pas ta syntaxe,
il faudrait une instruction spécifique du langage pour écrire : C1
n'implémente pas I.
Si on part du principe que tout ce qui n'est pas déclaré est faux, alors
mon écriture n'est plus possible non plus et le late binding n'a plus de
raison d'être.
Suis-je plus clair ?


--
Fred
http://www.cerber mail.com/?3kA6ftaCvT (enlever l'espace)
Avatar
Patrice
----- Original Message -----
From: "Fred"
Newsgroups: microsoft.public.fr.dotnet.vb
Sent: Monday, May 28, 2007 7:31 AM


Salut Fred.
Merci pour cette réponse mais à vrai dire, non, pas tout à fait.
Dans l'exemple que tu prends, on ne peut raisonnablement rien
attendre de mieux du compilateur, puisqu'on ne lui fournit aucune
info. En revanche, dans les deux miens, le compilateur sait que :
1) que V2 est de type C1 (et non object)
2) que C1 n'implémente pas I
3) que C1 ne fournit aucun cast spécifique vers I

A partir de là, je pense qu'il dispose de toutes les informations
nécessaires pour interdire le cast et refuser de compiler.

D'où mon entêtement, non d'une pipe, pourquoi est-ce possible ?? :)



C'est bien ce que j'ai compris, enfin, je crois :-). Le compilateur, dans
ton exemple, ne sait pas que V2 n'implémente pas I, même si toi, tu le
sais !



Ben c'est là que je loupe un truc alors. Je lui ai dit moi, au compilateur
(et poliment en plus). Plus exactement, je ne lui ai pas dit que C1
implémente I. Donc, jusqu'à nouvel ordre, C1 n'implémente pas I, donc, V2
qui est de type C1 ne peut en aucun cas être castable en I. Et ça c'est vrai
aussi bien pour le compilateur que pour moi, non ?

Donc il va générer du late binding. Et comme la variable V1 est juste
déclarée comme implémentant une interface, elle peut être de n'importe
quel type (comme mon object). Pourquoi alors interdire l'affectation à la
compilation ?



De fait tu as raison puisque c'est bien, semble-t-il, le raisonnement du
compilateur. Mais c'est justement ce qui me surprend. Tu dis que V1 "peut
être de n'importe quel type". Non, précisément. V1 peut être de n'importe
quel type implémentant I ! Ce qui fait une grosse nuance et élimine C1, et
devrait permettre de détecter l'erreur de type statiquement. Pas d'accord ?

Je pense même qu'on peut trouver un autre cas : imagine que V2, qui est de
type C1, soit en fait une instance d'une classe dérivée de C1, disons C3,
qui elle, implémenterait l'interface I ! (je n'ai pas testé si cette
construction est possible, mais j'en suis quasiment persuadé)
Le fait qu'une classe n'implémente pas explicitement une interface
n'interdit pas le fait qu'une instance de cette classe puisse tout de même
l'implémenter. Je le vois comme un cas particulier de mon exemple (Mon
objet n'implémente pas une interface qui contiendrait la méthode
«ExecuteUneMéthode»). Pour que le compilateur n'accepte pas ta syntaxe, il
faudrait une instruction spécifique du langage pour écrire : C1
n'implémente pas I.
Si on part du principe que tout ce qui n'est pas déclaré est faux, alors
mon écriture n'est plus possible non plus et le late binding n'a plus de
raison d'être.
Suis-je plus clair ?



Très clair en en effet, c'est évidemment l'explication. Donc ok, tu as
répondu, maintenant, ça devient de la philosophie.
J'ai rédigé mes réponses du dessus à la volée avant de lire ton dernier
paragraphe (j'aurais mieux fait de tout lire d'abord). Je les laisse tout de
même car elles illustrent ce qui me pose problème. Il me semble que l'on
pourrait tout à fait adopter une stratégie de compilation plus restrictive
sans pour autant remettre en cause le principe même du latebinding. A
m:inima, dans l'exemple que l'on prend, il suffirait d'interdire le cast
implicite dans CE cas.
Quand j'écris V1=Ctype(V2, I), je ne peux pas le faire par hasard, ça
signifie que je sais qu'à l'exécution certains V1 seront de d'une classe
implémentant I. Donc ok. Mais le compilo pourrait en plus m'imposer un try
catch avec catch InvalidCastException obligatoire par exemple parceque
j'aurai presque à coup sûr des erreurs de type qu'il serait bon de ne pas
oublier de traiter.

Je crois que c'est James Gosling qui disait que s'il devait réécrire Java,
il supprimerait les classes pour ne garder que les interfaces. En adoptant
cette stratégie et avec un compilateur ayant fait le choix de .Net (pareil
en C#) pour le typage, cela reviendrait à perdre tout la sûreté d'un typage
fort. J'ai du mal à croire que ce soit la seule solution. :)

Merci encore en tout cas.
Avatar
Patrice
Ce n'est pas si évident que cela me semble t'il...

Par exemple on pourrait utiliser v2 pour stocker une classe qui hérite de C1
et qui elle implémente cette interface. On n'est donc pas sûr à priori que
cela ne marchera pas dans aucune circonstance.

--
Patrice

"Patrice" a écrit dans le message de news:

Bonjour à tous,

J'ai une question dont j'ai presqe honte après qques années de dev.
dotnet. Quid de l'utilisation des interface et du typage statique ?
Naïvement, j'étais persuadé que le compilateur vérifiait statiquement
l'implémentation d'une interface par un objet lors de la sollicitation de
cette interface sur cet objet.

Exemple : disons que C1 est une classe n'implémentant pas une interface I.

il semble que ce code soit valide :

dim V1 as I
dim V2 as C1
V1=V2

ou encore :

V1=Ctype(V2, I)
Or on est statiquement certain que ce cast ne marche pas il me semble.

So ??? Tout est permi vraiment ??


Avatar
Patrice
Euh un autre Patrice ;-)

"Patrice" <http://www.chez.com/scribe/> a écrit dans le message de news:
%
Ce n'est pas si évident que cela me semble t'il...

Par exemple on pourrait utiliser v2 pour stocker une classe qui hérite de
C1 et qui elle implémente cette interface. On n'est donc pas sûr à priori
que cela ne marchera pas dans aucune circonstance.

--
Patrice

"Patrice" a écrit dans le message de
news:
Bonjour à tous,

J'ai une question dont j'ai presqe honte après qques années de dev.
dotnet. Quid de l'utilisation des interface et du typage statique ?
Naïvement, j'étais persuadé que le compilateur vérifiait statiquement
l'implémentation d'une interface par un objet lors de la sollicitation de
cette interface sur cet objet.

Exemple : disons que C1 est une classe n'implémentant pas une interface
I.

il semble que ce code soit valide :

dim V1 as I
dim V2 as C1
V1=V2

ou encore :

V1=Ctype(V2, I)
Or on est statiquement certain que ce cast ne marche pas il me semble.

So ??? Tout est permi vraiment ??






Avatar
Patrice
----- Original Message -----
From: "Patrice" <http://www.chez.com/scribe/>


Euh un autre Patrice ;-)




Ah merci de préciser, je me suis fait une frayeur, j'ai cru que je faisais
des crises de somnambulisme :)
Avatar
Patrice
"Patrice" <http://www.chez.com/scribe/> wrote in message
news:%
Ce n'est pas si évident que cela me semble t'il...

Par exemple on pourrait utiliser v2 pour stocker une classe qui hérite de
C1 et qui elle implémente cette interface. On n'est donc pas sûr à priori
que cela ne marchera pas dans aucune circonstance.



Oui très juste. Mais j'ai répondu à Fred sur l'autre branche du fil à ce
sujet. En tout cas, "techniquement" je suis d'accord, c'est normal.
Avatar
Patrice
> "Patrice" <http://www.chez.com/scribe/> wrote in message
news:%
Ce n'est pas si évident que cela me semble t'il...

Par exemple on pourrait utiliser v2 pour stocker une classe qui hérite de
C1 et qui elle implémente cette interface. On n'est donc pas sûr à priori
que cela ne marchera pas dans aucune circonstance.





Complément de réponse philosophique : le même raisonnement pourrait
s'appliquer aux classes elles-mêmes. Si j'appelle un membre sur une classe
qui ne l'implémente pas, rien ne me dit qu'à l'exécution, je n'aurais pas en
guisse d'instance de ma classe une sous-classe qui, elle, l'implémente.
Selon ce raisonnement, je devrait aussi l'accepter à la compilation. C'est
donc bien une question de choix, dans un cas comme dans l'autre. Et à mon
avis, ce devrait être le même. Si j'appelle un membre non implémenté sur une
variable d'interface, le cast explicite devrait être obligatoire. Une
interface est un type !