OVH Cloud OVH Cloud

Microsoft et Java

295 réponses
Avatar
Wykaaa
Microsoft semble reconnaître que Java permet de développer plus
rapidement que C# et qu'il y a moins de failles de sécurité dans Java
que dans .net :
http://dsi.silicon.fr/nouveautes/microsoft-java-forever%E2%80%A6-1366

10 réponses

Avatar
Jo Kerr
Aeris Imirhil avait soumis l'idée :


Sachant que « bar » provient d'une librairie dont tu n'as pas
forcément les sources, as-tu oublié des cas d'erreur ?
Aucun moyen de le savoir sauf à lire la doc en espérant qu'elle soit
complète…



Si un dev utilise une fonction d'une bibliothèque, la moindre des
choses c'est de s'assurer qu'elle est correctement documentée
(paramètres, valeurs de retour).

--
In gold we trust (c)
Avatar
JKB
Le Wed, 22 Jun 2011 01:59:12 -0700 (PDT),
Aeris Imirhil écrivait :
        Oui, et ? Elle est détectée, pas corrigée ! La bonne façon de faire,
        et dans _tous_ les langages, Java compris, c'est de commencer par
        écrire les bouts de traitement des erreurs et de ne pas déléguer ce
        traitement quand on aura du temps pour l'écrire !



Faux
La bonne façon de faire est d'écrire les traitements d'erreur
uniquement là où ils sont utiles (code critique) et de délégué à la
couche du dessus tout ce qu'on ne sait pas traité ou qu'il n'est pas
utile de traiter.



Je ne voudrais pas voir ta production. Mais chacun fait ce qu'il
veut.

        On se contre-fiche de la détection si on ne sait pas comment
        corriger facilement.



Euh…
Comment veux-tu corriger quelque chose que tu n'as pas détecté ?



Essaye de comprendre l'implication de ton assertion. On discutera
après. Tu n'as _pas_ compris ce que j'ai écrit.

        En C aussi figure-toi. On n'a pas attendu Java pour pointer les
        fonctions qui renvoyaient des valeurs non utilisées.



Ah, et comment ?

void foo(…) {
int t = writeToFile(filename, data);
}

Est-ce que « t » est un code d'erreur ou la taille réelle écrite ?

void foo(…) {
int t = writeToFile(filename, data);
if ( t == ERROR_FILE_NOT_AVAILABLE ) {

}
}

Est-ce que tous les cas d'erreur ont été traité ?



Ton exemple est typiquement du goret-codage. D'une part, si tu ne
sais pas quel est la prototype de la fonction, tu ferais bien de ne
pas l'utiliser. D'autre part, si tu veux être sûr de ne pas oublier
quelque chose, je te suggère de regarder du côté de switch (et des
macros ou fonctions inline qui sont faites pour gérer la palanquée
de code que tu vas rajouter et que tu n'aimes pas).

En C, la détection d'erreur est contextuelle (dépend du caractère de
la valeur de retour, de son domaine possible…), et donc non détectable
automatiquement sans erreur.



Hein ?

La seule détection possible devrait analyser en profondeur le code.



Exprime-toi en français parce que j'ai beau lire et relire cette
phrase, je n'en comprends toujours pas le sens.

Dans l'exemple précédent, elle nécessite la connaissance du code de la
fonction « writeToFile » et l'analyse de toutes les valeurs de retour
possibles.



Non. Elle nécessite de connaître le prototype de la fonction. Point
barre. Et en Java, si tu ne connais pas le prototype d'une fonction,
tu ne vas pas loin non plus.

Et même comme ça, on n'a aucun moyen de différencier « int
writeToFile(char* file, char* data, int* written) » de « int
writeToFile(char* file, char* data) », la 1ère ayant un code d'erreur,
la 2nde non (taille de l'écriture).



Euh, comment dire... En C, peut-être. En C++, c'est trivial.

> — sans propagation de l'erreur

        Gnî ?



int foo(…) {
if ( bar() == ERROR_BAR_1 ) {

}
}

int bar(…) {
if ( fooBar() == ERROR_FOO_BAR_1 ) {
return ERROR_BAR_1;
}
// Oublie de ERROR_FOO_BAR_2
}



Parce qu'on ne gère pas ça comme ça. Effectivement, si c'est ton
niveau de programmation C/C++, reste avec Java !

Le fait d'avoir oublié le cas ERROR_FOO_BAR_2 dans « bar » fait qu'on
a propagé l'erreur aussi dans « foo ».



Parce que le code est _mauvais_. Sans macro et développé, ce code
est :

int
bar()
{
int ios;

switch(ios = fooBar())
{
case 0:
...
break;

case ERROR_FOO_BAR_1:
...
case ERROR_FOO_BAR_2:
...
default:
...
}

return;
}

Tu as parfaitement le droit de faire autrement, mais c'est _ton_
problème. Pour ta gouverne, avec une macro bien sentie, ce code est
chez moi :

CHECK(fooBar(), <...>);

où <...> contient la liste des trucs à faire pour libérer les
ressources en cas d'erreur. C'est donc vachement compliqué. CHECK
est une macro triviale et tout à fait maintenable.

Les 2 codes sont à modifier en cas de correction de « bar », sauf que
l'erreur ne sera détectée que sur « bar », et sur « foo » uniquement
sur une autre itération de relecture de code.

En Java, au pire, l'ajout d'une exception sur « bar » la fera remonter
jusqu'à ce que le compilateur geule.
La correction de TOUS les morceaux de code impactés se fera sur la
même itération de relecture.



...

Tu peux déjà te débrouiller
        pour que la valeur de retour soit récupérée. Si après, l'utilisateur
        ne la traite pas, le problème est strictement le même qu'en Java.



Non.
Tu n'as pas la possibilité de ne pas traiter une exception en Java, le
compilateur t'impose soit de la remonter au-dessus (« throw
FooException ») soit de la try-catch.



C'est exactement ce que je dis. Et je rajoute que le try-catch-all
est une moisissure du langage.

Aucune possibilité de rater une erreur ou de ne pas la traiter.



Si. Si tu ne vois pas comment faire, je ne peux rien pour toi.

En C, pour faire plaisir à tes moulinettes de code, tu vas donc en
plus devoir au moins lire toutes les valeurs de retour de toutes tes
fonctions, et non uniquement tes codes d'erreur (aucun moyen de les
différencier facilement).



?

Ce qui complexifie encore le code pour que dalle.
Par exemple dans « int writeToFile(char* filename, char* data) », la
valeur de retour est totalement inutile dans 99% des cas pour la suite
du programme.



En C, aucune valeur de retour est inutile. Effectivement, si tu pars
de cette hypothèse, je comprends mieux ta réaction épidermique.

        Pardon ? Ces valeurs de retour sont _normalisées_ et parfaitement
        _connues_.



Ah ?

int foo(…) {
if ( bar() == ERROR_BAR ) {

}
}



On parlait des appels système. Maintenant, tu as le droit de définir
en plus tes propres valeurs d'erreur. Mais tu les connais à ce
moment parfaitement (où alors il te faut changer de métier parce que
tu ne sais plus vraiment ce que tu fais).

Sachant que « bar » provient d'une librairie dont tu n'as pas
forcément les sources, as-tu oublié des cas d'erreur ?



Pas possible avec le default: du switch. Si ça ne te vas pas, tu
peux aussi utiliser un else{} dans ta close if().

Aucun moyen de le savoir sauf à lire la doc en espérant qu'elle soit
complète…



On s'en contrefiche. Le else ou le default est justement là pour ça.
Et si la doc ne correspond pas à la fonction, je te rappelle que
c'est exactement la même chose en C, C++, Fortran, Algol, Java ou
tout langage que tu peux imaginer.

> — aucun moyen de savoir si TOUTES les fonctions appelantes traitent TOUS
> les cas d'erreur possibles de TOUTES les fonctions appelées
> il est impossible de garantir si le code qu'on a sous les yeux est
> correct ou non et s'il traite correctement les erreurs, et encore moins
> de manière automatisée.

        C'est parfaitement possible. C'est même l'hygiène de base du
        développeur C et pour ma part, il y a longtemps que j'ai automatisé
        la tâche.



Explique-nous, Ô Grand Dieu de la programmation, comment peux-tu
détecter si le code suivant est correct :

int foobar(…) {
bar(1);
if ( foo(…) == ERROR_FOO ) {

}
}



On ne parlais pas de ça, mais de codes de retour ignorés. On peut
détecter ça avec quelques macros. Démerde-toi pour les trouver.

Sachant que tu n'as peut-être pas le source des fonctions « int foo(…)
» et « int bar(int i) », qu'elles proviennent peut-être d'une
librairie sur étagère ou d'une autre équipe de dev.



On s'en fout. On regarde l'appel de la fonction qui peut être une
boîte opaque.

Comment fais-tu la différence entre :
int bar(int i) {

if ( i > 0 ) return 1;
return -1;
}
qui conduit à un code correct (la valeur de retour n'étant pas
intéressante et pas un code d'erreur pour la suite de notre programme)
et :
int bar(int i) {

if ( bar1() == ERROR_BAR1 )
return ERROR_BAR;
return 0;
}
qui conduit à un code incorrect (oubli d'un cas d'erreur)



Tu relis le prototypage de ta fonction.

Ou encore, comment différencies-tu :
int foo(…) {

if ( foo1() == ERROR_FOO1 )
return ERROR_FOO;
return 0;
}
qui donne un code correct
et :
int foo(…) {

if ( foo1() == ERROR_FOO1 )
return ERROR_FOO;
if ( foo2() == ERROR_FOO2 )
return ERROR_FOO_1;
return 0;
}
qui le rend incorrect (oubli d'un cas d'erreur) ?

J'attend ton explication avec impatience =)



Il n'y a rien à dire. Si tu n'es pas capable de lire un prototype,
tu devrais changer de métier. En fait, ton problème, c'est de
remonter une erreur sur une variable parce que ça t'oblige à faire
attention à tes paramètres d'entrée et de sortie. Un exception,
c'est 'achement bien, parce que je peux gérer ça comme un porc, ça
sera toujours récupéré par un gestionnaire d'exception. Le reste
n'est que du blabla pour essayer de justifier ta position.

En fonction du contenu et du comportement des méthodes appelées, ton
code appelant peut être correct… ou pas =)



Argutie.

Donc la détection d'erreur est contextuelle et donc non automatisable.



Non plus.

En Java, la seule connaissance de la signature de la méthode indique
quelles erreurs sont à traiter, le code n'est pas contextuel et est
soit correct (il compile) soit non (il ne compile pas).
L'implémentation interne de la méthode appelée n'influe pas sur la
correction de la méthode appelante.



Euh, comment dire... Les bras m'en tombent... On parle de gestion
des erreurs et non du fait qu'un code est joli ou non, ou compile ou
non.

        Euh... Comment dire... Tu viens de prouver en une ligne que tu n'as
        aucune idée de la façon dont on fait une revue de code ou des tests
        de code.



J'en passe toutes les semaines des revues de code…



Peut-être en Java, mais certainement pas en C. Tout ce que tu
prétends faire en Java (et je ne remets pas en cause tes compétences
en Java) se fait aussi en C/C++. Visiblement, tu n'es pas au
courant.

Tester la remontée des erreurs en C est un truc qui se fait
        à partir de macros.



Cf code du dessus…
Et tu fais comment pour les méthodes que tu n'as pas écrites toi-même
(COTS, librairies d'une autre équipe…) ?



PARCE QU'ON N'A PAS À REGARDER LE CODE INTERNE. ON SE CONTENTE DES
PROTOTYPES, CE QUI SUFFIT AMPLEMENT !

Je ne vais pas passer deux heures à t'expliquer
        comment, mais il est très simple de provoquer une erreur en C et de
        voir ce qui se passe.



Ça ça s'appelle des tests U.
Et c'est même encore plus simple en Java (JUnit + EasyMock + IoC)

        Non. Avec quelques scripts générant des fichiers d'en-têtes, c'est même
        automatique.




Ne me dis quand même pas que tu vas modifier des fichiers de code qui
finiront en prod pour tester ta complétitude et ta fiabilité ?



Non, je t'ai parlé d'en-tête pour tester les propagations d'erreur.
Ces en-têtes sont générées automatiquement pour traiter toutes les
erreurs et sont simplement déactivées lorsque le truc est compilé
avec -UDEBUG. Aucun code source n'est modifié dans le sens où tu
l'entends.

JKB

--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse...
=> http://grincheux.de-charybde-en-scylla.fr
Avatar
Yliur
> Est-ce que les gens qui
> écrivent Apache (par exemple) sont des grosses quiches ? Ou est-ce
> que le fait qu'il y ait 255 trucs à se rappeler par ligne de code
> peut intervenir ?

Le problème du C n'est _pas_ là. C'est dans les dépassements
de buffer la plupart du temps, dans l'arithmétique des pointeurs (ou
dans les variables non initialisées, mais on a le même dans Java).



Plus le développeur a de choses à se rappeler par ligne de code, plus
il risque de faire des erreurs.

Le problème des variables non initialisées est moins important en Java,
même si ça peut se poser aussi dans certains cas.


>> Lorsqu'il reste un pointeur quelque part qui pointe sur une
>> zone de la mémoire, cette zone n'est pas libérée. C'est un effet
>> pervers du GC, que tu le veuilles ou non. Et ce genre de bêtise est
>> très vite fait.
>
> Pas plus qu'en C. En Java on ne le fait pas partout, on se concentre
> sur les quelques ressources concernées, c'est tout. Et il y en a
> peu. Le cas que tu cites est assez rare.

Et assez pour mettre le bazar.



Je ne dis pas qu'on ne peut pas faire de conneries, simplement que le
nombre d'endroits à surveiller est moins important et que c'est donc
plus simple.
Avatar
Yliur
Le Tue, 21 Jun 2011 16:46:23 -0400
Dellara a écrit :

> Ben je t'ai déjà répondu que le développeur pressé fera aussi des
> conneries en C, c'est pareil.

Tu sais, ce serait beaucoup mieux si tu citais le contribruiteur à
qui tu réponds.



Son nom, tu veux dire ?


Cette pratique antédiluvienne consistant à obliger le
lecteur à se taper un fil interminable pour suivre la conversation
est vraiment d'un autre âge.



?
Je ne vois pas bien le rapport avec la première demande. Parce que
c'est difficile de voir à quel message ma réponse est rattachée ?
Avatar
JKB
Le Wed, 22 Jun 2011 13:58:41 +0200,
Yliur écrivait :
Le Tue, 21 Jun 2011 16:46:23 -0400
Dellara a écrit :

> Ben je t'ai déjà répondu que le développeur pressé fera aussi des
> conneries en C, c'est pareil.

Tu sais, ce serait beaucoup mieux si tu citais le contribruiteur à
qui tu réponds.



Son nom, tu veux dire ?


Cette pratique antédiluvienne consistant à obliger le
lecteur à se taper un fil interminable pour suivre la conversation
est vraiment d'un autre âge.



?
Je ne vois pas bien le rapport avec la première demande. Parce que
c'est difficile de voir à quel message ma réponse est rattachée ?



Honnêtement ? Oui, parce que tu ne coupes que ce qui t'intéresse
histoire de dénaturer les propros.

JKB

--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse...
=> http://grincheux.de-charybde-en-scylla.fr
Avatar
remy
JKB a écrit :



bar()
{
int ios;

switch(ios = fooBar())
{
case 0:
...
break;

case ERROR_FOO_BAR_1:
...
case ERROR_FOO_BAR_2:
...
default:
...
}
....
return codeErreuraLaCom;
}





bar0()
{
int ios;
witch(ios = bar())
{
case 0:
....
}
---
codeErreuraLaCom0;
}

bar1()
{
int ios;
witch(ios = bar0())
{
case 0:
....
}
....
return codeErreuraLaCom;
}

bar2()
{
int ios;
witch(ios = bar1())
{
case 0:
....
}
...
return codeErreuraLaCom;
}

Openbar()
{
int ios;
witch(ios = bar2())
{
case 0:
....
}
...
return hip;
}

question combien de fois le test le code erreur a la con ?

comment évité cette perte de temps inutile et stupide ne me di t pas
avec une rupture de contexte ou avec quelque chose qui s'apparente a de
la programmation l'évènementiel

si oh non ...


remy






--
http://remyaumeunier.chez-alice.fr/
Avatar
Aeris Imirhil
On 22 juin, 13:09, JKB wrote:
        Ton exemple est typiquement du goret-codage. D'une part, si tu ne
        sais pas quel est la prototype de la fonction, tu ferais bien de ne
        pas l'utiliser.



Il ne s'agit pas de connaître uniquement le prototype de la fonction
mais la signification exacte de sa valeur de retour : est-ce une
donnée de retour ou un code d'erreur ?
le « int » de « int foo(…) » peut dénoter à la fois un code d'erreur
ou autre chose, et on ne fait pas du tout la même chose en fonction du
cas : dans le 1er la valeur DOIT être traitée, dans le 2nd, elle PE UT
être traitée (fonction de son utilité réelle dans ton code).

D'autre part, si tu veux être sûr de ne pas oublier
        quelque chose, je te suggère de regarder du côté de switch



Switch ou pas, tu n'as aucun moyen d'être sûr de n'avoir raté aucun
code d'erreur…

> En C, la détection d'erreur est contextuelle (dépend du caractère de
> la valeur de retour, de son domaine possible…), et donc non détecta ble
> automatiquement sans erreur.

        Hein ?



int bar();

void foo() {
…
bar();
…
}

Ce code peut tout à fait être correct, comme il peut ne pas l'être.
Si le « int » renvoyé n'est pas un code d'erreur mais une valeur
métier, le code est correct.
S'il est un code d'erreur, ce code n'est pas correct et devrait
s'écrire :

void foo() {
…
switch ( bar() ) {
case ERROR_BAR:
…
}
…
}

Le soucis devient alors d'être sûr d'avoir couvert l'intégralité de s
cas d'erreur et leur reprise sur faute éventuelle.
Et là tu es 100% dépendant de la correction de la doc de la fonction
et/ou de la disponibilité de son code.
Sans au moins 1 des 2 éléments, aucun moyen d'écrire un code fiable
(i.e. traitant tous les cas possibles)

Sauf à écrire :

void foo() {
…
if ( bar() != 0) {
handleError();
}
…
}
il n'y a aucun moyen de garantir la fiabilité du code, mais cet
exemple revient exactement à un try/finally Java, avec en plus
l'impossibilité de traiter les cas d'erreurs unitairement (catch
(IOException) catch (FileException) …)

Le seul moyen en C d'écrire un code fiable et traitant les types
d'erreur unitairement est d'écrire :

void foo() {
…
switch ( bar() ) {
case ERROR_BAR_1:
…
case ERROR_BAR_2:
…
case ERROR_BAR_3:
…
}
…
}

mais tu n'as aucun moyen fiable de connaître la plage de valeur du
code de retour de « bar » sans sa doc ou son source : son prototype ne
suffit pas.

> La seule détection possible devrait analyser en profondeur le code.

        Exprime-toi en français parce que j'ai beau lire et rel ire cette
        phrase, je n'en comprends toujours pas le sens.



Cf exemple plus haut.
Aucun moyen de détecter une erreur sans connaître parfaitement
*l'IMPLÉMENTATION* (ou en tout cas la doc) de la fonction appelée. Sa
signature ne suffit pas en soi et un même code pour les mêmes
signatures peut être correct ou buggé fonction de l'implémentation de s
appelés.
La seule possibilité d'avoir l'assurance d'un code correct en C est de
connaître (via le code ou la doc) l'intégralité du contenu d'un proje t
et de toutes ses dépendances, là où en Java la signature de la méth ode
suffit.

« int foo(…) » ne peut me renseigner seule sur l'ensemble des erreurs
potentielles. Son implémentation réelle est nécessaire ou l'accès à sa
doc (qui peut être fausse, inexistante ou incomplète).
« void foo(…) throws FileNotFoundException, IOException » contient en
elle-même toutes les infos nécessaires à un code fiable, y compris le s
cas d'erreur à traiter, quelque soit l'état de sa doc (même fausse,
inexistante ou incomplète) ou la disponibilité de son code.

> Dans l'exemple précédent, elle nécessite la connaissance du code de la
> fonction « writeToFile » et l'analyse de toutes les valeurs de retour
> possibles.

        Non. Elle nécessite de connaître le prototype de la f onction. Point
        barre.



Non, de sa plage de valeur de retour admissible aussi.
Si elle peut renvoyer 0 et -1, je n'ai pas le même code à écrire que
si elle renvoie 0, -1 (ERROR_FILE) et -2 (ERROR_IO).

> Et même comme ça, on n'a aucun moyen de différencier « int
> writeToFile(char* file, char* data, int* written) » de « int
> writeToFile(char* file, char* data) », la 1ère ayant un code d'er reur,
> la 2nde non (taille de l'écriture).

        Euh, comment dire... En C, peut-être. En C++, c'est tri vial.



Je te parle de la valeur de retour.
Aucun moyen de savoir si un « int » est une valeur métier ou un c ode
de retour…

        Parce qu'on ne gère pas ça comme ça. Effectivement, si c'est ton
        niveau de programmation C/C++, reste avec Java !



Met tes switch si tu préfères, le problème reste le même.

int
bar()
{
        int ios;

        switch(ios = fooBar())
        {
                case 0:
                ...
                        break;

                case ERROR_FOO_BAR_1:
                ...
                case ERROR_FOO_BAR_2:
                ...
                default:
                ...
        }

        return;

}



Tu ne comprends vraiment rien au problème toi…
Le problème n'est pas de savoir si « if » est meilleur que «  switch »,
mais du nombre de cas à traiter pour être complet…
Le fait de ne pas être totalement couvrant dans « bar » fera qu'a près
correction, toutes les méthodes appelantes de « bar » vont aussi
devenir non totalement couvrantes.
Le fait d'avoir oublié un cas dans « bar » fait qu'on en a
automatiquement oublié dans « foo » qui appelle « bar » e t que
« foo », correct avec « bar » buggé, deviendra buggé av ec « bar » non
buggé.
C'est ça de la propagation d'erreur : en C, le fait de corriger un
bout de code sur la gestion d'erreur t'impacte toutes tes méthodes
appelantes aussi sur la gestion d'erreur !

        Tu as parfaitement le droit de faire autrement, mais c'es t _ton_
        problème. Pour ta gouverne, avec une macro bien sentie, ce code est
        chez moi :

        CHECK(fooBar(), <...>);

        où <...> contient la liste des trucs à faire pour lib érer les
        ressources en cas d'erreur. C'est donc vachement compliqu é. CHECK
        est une macro triviale et tout à fait maintenable.



Et donc tu es strictement équivalent à un catch-all Java…
Et incapable de gérer les types d'erreurs correctement.

int fooBar(…) {
…
return ERROR_FILE_UNVAILABLE;
…
return ERROR_IO_ERROR;
…
}

« CHECK(fooBar(), <...>); » te rend incapable de faire la distincti on
entre une erreur fichier (le nom du fichier était incorrect) et
d'écriture (le disque est mort ?), et de réagir différemment en
conséquence.

> Les 2 codes sont à modifier en cas de correction de « bar », sauf que
> l'erreur ne sera détectée que sur « bar », et sur « foo  » uniquement

        C'est exactement ce que je dis. Et je rajoute que le try- catch-all
        est une moisissure du langage.



Qui est strictement équivalente à ta macro « CHECK », la possibil ité
de distinguer les types d'erreur en moins…
Si c'est une moississure du langage, ton code est donc une moisissure
de moisissure…

        En C, aucune valeur de retour est inutile.



int write(…) {
…
return sizeWritten;
}

Celle-là est inutile potentiellement.

int write(…) {
…
return ERROR_FILE;
…
}

Celle-là est non seulement pas inutile mais en plus doit
OBLIGATOIREMENT être testée après appel !

        Pas possible avec le default: du switch. Si ça ne te va s pas, tu
        peux aussi utiliser un else{} dans ta close if().



Ce qui est encore plus équivalent à un try-catch en Java…

        Et si la doc ne correspond pas à la fonction, je te rap pelle que
        c'est exactement la même chose en C, C++, Fortran, Algo l, Java ou
        tout langage que tu peux imaginer.



Faux
Si le mec a dans sa lib une fonction « void foo() throws
FileException », même s'il oublie de documenter l'erreur ou la
documente mal, le compilateur refusera de compiler mon code si je ne
traite pas l'erreur !
En Java, je ne suis pas dépendant des sources ou de la doc, uniquement
du code RÉEL (et non du comportement ou de la doc SUPPOSÉS corrects).
Si le mec a oublié de documenter un cas d'erreur, je serais quand même
obligé de le traiter dans mon code pour compiler !

        On ne parlais pas de ça, mais de codes de retour ignor és. On peut
        détecter ça avec quelques macros. Démerde-toi pour les trouver.



Cf l'exemple…
Le code est correct ou pas en fonction du comportement réel de la
fonction
Aucune macro ni algo n'est capable de détecter cette erreur !

> Sachant que tu n'as peut-être pas le source des fonctions « int f oo(…)
> » et « int bar(int i) », qu'elles proviennent peut-être d'une
> librairie sur étagère ou d'une autre équipe de dev.

        On s'en fout. On regarde l'appel de la fonction qui peut être une
        boîte opaque.



Et tu fais comment pour connaître tous les codes de retour possibles
et imaginables ?
Sans être équivalent à un catch-all Java que tu sembles critiquer ?



> Comment fais-tu la différence entre :
>     int bar(int i) {
>         …
>         if ( i > 0 ) return 1;
>         return -1;
>     }
> qui conduit à un code correct (la valeur de retour n'étant pas
> intéressante et pas un code d'erreur pour la suite de notre programme )
> et :
>     int bar(int i) {
>         …
>         if ( bar1() == ERROR_BAR1 )
>             return ERROR_BAR;
>         return 0;
>     }
> qui conduit à un code incorrect (oubli d'un cas d'erreur)

        Tu relis le prototypage de ta fonction.



Le prototype est le même dans les 2 cas : « int bar(int) »

        Il n'y a rien à dire. Si tu n'es pas capable de lire un prototype,
        tu devrais changer de métier.



Le prototype est toujours le même dans les 2 cas : « int foo(…)  »…
Tu es désespérant comme mec…

En fait, ton problème, c'est de
        remonter une erreur sur une variable parce que ça t'obl ige à faire
        attention à tes paramètres d'entrée et de sortie.



Non, mon problème est qu'à la vue du prototype d'une fonction en C, je
n'ai :
— Aucun moyen de savoir si elle me retourne un code d'erreur ou un
retour métier ( « int write(…) » peut aussi bien me retourner l a
taille écrite qu'un code d'erreur)
— S'il s'agit d'un code d'erreur, l'ensemble des codes d'erreur
possibles afin que je puisse distinguer les types d'erreur pour les
traiter différemment suivant le cas si besoin ( « int write(…)  » peut
aussi bien me retourner 0 pour le succès et -1 pour l'erreur que 0
pour le succès, -1 pour un fichier inexistant, -2 pour un fichier sans
droit d'écriture, -3 pour une erreur de flux…)

        Argutie.



Cf multiples exemples au-dessus.

Et pour t'en donner un de plus, le code suivant est-il fiable, Ô Grand
Dieu ?

int write(char *file, char *data); // Issu d'une bibliothèque d'une
autre équipe de dev

void foo() {
write("/tmp/bar.txt", "Hello World !");
}

> Donc la détection d'erreur est contextuelle et donc non automatisable .

        Non plus.



Répond à la question ci-dessus, on commentera ce « non plus » apr ès.

plus de détails »



Répond à la question ci-dessus, je te donne les détails après ta
réponse
Avatar
JKB
Le Wed, 22 Jun 2011 05:47:49 -0700 (PDT),
Aeris Imirhil écrivait :
On 22 juin, 13:09, JKB wrote:
        Ton exemple est typiquement du goret-codage. D'une part, si tu ne
        sais pas quel est la prototype de la fonction, tu ferais bien de ne
        pas l'utiliser.



Il ne s'agit pas de connaître uniquement le prototype de la fonction
mais la signification exacte de sa valeur de retour : est-ce une
donnée de retour ou un code d'erreur ?



Ça, mon grand, c'est spécifié dans le prototype et l'interface.

le « int » de « int foo(…) » peut dénoter à la fois un code d'erreur
ou autre chose, et on ne fait pas du tout la même chose en fonction du
cas : dans le 1er la valeur DOIT être traitée, dans le 2nd, elle PEUT
être traitée (fonction de son utilité réelle dans ton code).



Idem.

Je suis désolé, mais je coupe ton blabla totalement inintéressant.
Je maintiens que tu n'as pas besoin de savoir comment est fichue une
fonction à partir du moment où tu connais son interface. Si tu ne
connais pas son interface, le problème est le même avec tous les
langages. Tu n'as absolument pas besoin de connaître tout un projet,
c'est même l'un des avantages de la programmation fonctionnelle.

« int foo(…) » ne peut me renseigner seule sur l'ensemble des erreurs
potentielles. Son implémentation réelle est nécessaire ou l'accès à sa
doc (qui peut être fausse, inexistante ou incomplète).



Te rends-tu compte que ton argument est parfaitement idiote ? Si la
doc est mauvaise, il est _normal_ que le code utilisant ladite
bibliothèque soit buggué. Et alors ? La seule différence dans ce cas
est que le compilo Java va gueuler, mais ce n'est pas pour cela que
ton code sera bon. Tu vas juste rajouter un truc pour récupérer
l'exception machin-chose qui pourrait arriver. Et c'est sans compter
que le throw de la signature est peut-être un résidu qui ne sert
plus. Tu n'as _aucun_ moyen de le savoir.

« void foo(…) throws FileNotFoundException, IOException » contient en
elle-même toutes les infos nécessaires à un code fiable, y compris les
cas d'erreur à traiter, quelque soit l'état de sa doc (même fausse,
inexistante ou incomplète) ou la disponibilité de son code.



Non, parce que tu es _obligé_ de faire confiance à cette ligne qui
peut comporter des choses amusantes voire totalement fausses.

> Dans l'exemple précédent, elle nécessite la connaissance du code de la
> fonction « writeToFile » et l'analyse de toutes les valeurs de retour
> possibles.

        Non. Elle nécessite de connaître le prototype de la fonction. Point
        barre.



Non, de sa plage de valeur de retour admissible aussi.
Si elle peut renvoyer 0 et -1, je n'ai pas le même code à écrire que
si elle renvoie 0, -1 (ERROR_FILE) et -2 (ERROR_IO).



Par prototype, j'entendais prototype _et_ interface. Ne fais pas
semblant de ne pas avoir compris.

> Et même comme ça, on n'a aucun moyen de différencier « int
> writeToFile(char* file, char* data, int* written) » de « int
> writeToFile(char* file, char* data) », la 1ère ayant un code d'erreur,
> la 2nde non (taille de l'écriture).

        Euh, comment dire... En C, peut-être. En C++, c'est trivial.



Je te parle de la valeur de retour.
Aucun moyen de savoir si un « int » est une valeur métier ou un code
de retour…



Arrête de te raccrocher aux branches, ça commence à se voir. Tu
_dois_ connaître l'interface d'une fonction avant de l'utiliser.
Enfin, c'est préférable.

        Parce qu'on ne gère pas ça comme ça. Effectivement, si c'est ton
        niveau de programmation C/C++, reste avec Java !



Met tes switch si tu préfères, le problème reste le même.



Non. Je te rappelle que tu prétendais qu'en C, on pouvait rater une
erreur. Je viens de te démontrer que c'est faux (que ce soit avec
des switchs ou avec des if/else).

int
bar()
{
        int ios;

        switch(ios = fooBar())
        {
                case 0:
                ...
                        break;

                case ERROR_FOO_BAR_1:
                ...
                case ERROR_FOO_BAR_2:
                ...
                default:
                ...
        }

        return;

}



Tu ne comprends vraiment rien au problème toi…
Le problème n'est pas de savoir si « if » est meilleur que « switch »,
mais du nombre de cas à traiter pour être complet…
Le fait de ne pas être totalement couvrant dans « bar » fera qu'après
correction, toutes les méthodes appelantes de « bar » vont aussi
devenir non totalement couvrantes.
Le fait d'avoir oublié un cas dans « bar » fait qu'on en a
automatiquement oublié dans « foo » qui appelle « bar » et que
« foo », correct avec « bar » buggé, deviendra buggé avec « bar » non
buggé.



Je ne vois pas comment tu peux en oublier sachant que tu gères
l'erreur à chaque appel (et de façon automatique avec une macro).

C'est ça de la propagation d'erreur : en C, le fait de corriger un
bout de code sur la gestion d'erreur t'impacte toutes tes méthodes
appelantes aussi sur la gestion d'erreur !



Non, d'autant qu'il n'y a pas de méthode en C.

        Tu as parfaitement le droit de faire autrement, mais c'est _ton_
        problème. Pour ta gouverne, avec une macro bien sentie, ce code est
        chez moi :

        CHECK(fooBar(), <...>);

        où <...> contient la liste des trucs à faire pour libérer les
        ressources en cas d'erreur. C'est donc vachement compliqué. CHECK
        est une macro triviale et tout à fait maintenable.



Et donc tu es strictement équivalent à un catch-all Java…
Et incapable de gérer les types d'erreurs correctement.

int fooBar(…) {

return ERROR_FILE_UNVAILABLE;

return ERROR_IO_ERROR;

}

« CHECK(fooBar(), <...>); » te rend incapable de faire la distinction
entre une erreur fichier (le nom du fichier était incorrect) et
d'écriture (le disque est mort ?), et de réagir différemment en
conséquence.



Mais bien sûr que si. Je ne t'ai pas donné le contenu de la macro en
question. La macro traite les erreurs dans un switch et une fois
l'erreur traitée, elle libère les ressources en rendant la main à
l'appelant. Elle fait exactement ce qu'il faut pour chacune des erreurs.

> Les 2 codes sont à modifier en cas de correction de « bar », sauf que
> l'erreur ne sera détectée que sur « bar », et sur « foo » uniquement



        C'est exactement ce que je dis. Et je rajoute que le try-catch-all
        est une moisissure du langage.



Qui est strictement équivalente à ta macro « CHECK », la possibilité
de distinguer les types d'erreur en moins…
Si c'est une moississure du langage, ton code est donc une moisissure
de moisissure…



Absolument pas. D'un autre côté, je ne cherche pas à te convertir.
Vu tes arguments, reste avec Java, il vaut mieux.

        En C, aucune valeur de retour est inutile.



int write(…) {

return sizeWritten;
}

Celle-là est inutile potentiellement.

int write(…) {

return ERROR_FILE;

}

Celle-là est non seulement pas inutile mais en plus doit
OBLIGATOIREMENT être testée après appel !



Qu'est-ce que tu cherches à dire ? Qu'en C, il vaut mieux connaître
les interfaces des fonctions ? C'est une tautologie !

        Pas possible avec le default: du switch. Si ça ne te vas pas, tu
        peux aussi utiliser un else{} dans ta close if().



Ce qui est encore plus équivalent à un try-catch en Java…



Pas exactement, relis-moi attentivement (avec les exemples donnés).

        Et si la doc ne correspond pas à la fonction, je te rappelle que
        c'est exactement la même chose en C, C++, Fortran, Algol, Java ou
        tout langage que tu peux imaginer.



Faux
Si le mec a dans sa lib une fonction « void foo() throws
FileException », même s'il oublie de documenter l'erreur ou la
documente mal, le compilateur refusera de compiler mon code si je ne
traite pas l'erreur !



Et tu te retrouves _aussi_ à gérer des erreurs qui n'existent plus
parce que le type à laissé un throws bizarre dans le fichier.
Merci, j'ai donné.

En Java, je ne suis pas dépendant des sources ou de la doc, uniquement
du code RÉEL (et non du comportement ou de la doc SUPPOSÉS corrects).
Si le mec a oublié de documenter un cas d'erreur, je serais quand même
obligé de le traiter dans mon code pour compiler !



Et de le traiter en aveugle ou presque. C'est bien. On a une doc
fausse, un code qui ne compile pas, puis on rajoute un gestionnaire
d'exception parce que le compilo te le demande... Et tu ne trouves
pas ça aberrant ou casse-gueule ?

        On ne parlais pas de ça, mais de codes de retour ignorés. On peut
        détecter ça avec quelques macros. Démerde-toi pour les trouver.



Cf l'exemple…
Le code est correct ou pas en fonction du comportement réel de la
fonction
Aucune macro ni algo n'est capable de détecter cette erreur !



Je te rappelle (parce que tu coupes tellement qu'on n'arrive plus à
suivre) que le problème initial était de savoir si les valeurs de
retour étaient récupérées ou non. Je prétends qu'avec quelques
macros bien senties tu peux t'en assurer. Il n'était pas question
initialement de savoir comment elles étaient traitées.

> Sachant que tu n'as peut-être pas le source des fonctions « int foo(…)
> » et « int bar(int i) », qu'elles proviennent peut-être d'une
> librairie sur étagère ou d'une autre équipe de dev.

        On s'en fout. On regarde l'appel de la fonction qui peut être une
        boîte opaque.



Et tu fais comment pour connaître tous les codes de retour possibles
et imaginables ?
Sans être équivalent à un catch-all Java que tu sembles critiquer ?



Il y a une doc. C'est l'hypothèse de base. De toute façon, même avec
Java, je REFUSE de coder un truc lorsqu'un appel de fonction ne
réagit pas comme cela est expliqué dans la DOC. Moi, mon truc, c'est
le calcul. Et si une fonction est censée tourner avec un integer*4,
que c'est marqué dans la doc, je suppose que c'est vrai.

Par ailleurs, si la doc ne correspond pas à l'interface réelle de la
fonction, il y a de fortes chances que l'intérieur de la fonction
elle-même soit légèrement différente, ce qui implique non seulement
d'autres erreurs à traiter, mais aussi des fonctionnalités
différentes. Bref, mon expérience me dit que lorsqu'un truc n'est
pas conforme à la doc, il vaut mieux ne pas l'utiliser. Après, tu
fais ce que tu veux.

> Comment fais-tu la différence entre :
>     int bar(int i) {
>         …
>         if ( i > 0 ) return 1;
>         return -1;
>     }
> qui conduit à un code correct (la valeur de retour n'étant pas
> intéressante et pas un code d'erreur pour la suite de notre programme)
> et :
>     int bar(int i) {
>         …
>         if ( bar1() == ERROR_BAR1 )
>             return ERROR_BAR;
>         return 0;
>     }
> qui conduit à un code incorrect (oubli d'un cas d'erreur)

        Tu relis le prototypage de ta fonction.



Le prototype est le même dans les 2 cas : « int bar(int) »

        Il n'y a rien à dire. Si tu n'es pas capable de lire un prototype,
        tu devrais changer de métier.



Le prototype est toujours le même dans les 2 cas : « int foo(…) »…
Tu es désespérant comme mec…



Non, tout le monde avait compris (sauf toi visiblement), que
j'entendais pas prototype, prototype _et_ interface.

En fait, ton problème, c'est de
        remonter une erreur sur une variable parce que ça t'oblige à faire
        attention à tes paramètres d'entrée et de sortie.



Non, mon problème est qu'à la vue du prototype d'une fonction en C, je
n'ai :
— Aucun moyen de savoir si elle me retourne un code d'erreur ou un
retour métier ( « int write(…) » peut aussi bien me retourner la
taille écrite qu'un code d'erreur)
— S'il s'agit d'un code d'erreur, l'ensemble des codes d'erreur
possibles afin que je puisse distinguer les types d'erreur pour les
traiter différemment suivant le cas si besoin ( « int write(…) » peut
aussi bien me retourner 0 pour le succès et -1 pour l'erreur que 0
pour le succès, -1 pour un fichier inexistant, -2 pour un fichier sans
droit d'écriture, -3 pour une erreur de flux…)



Et ? La doc n'est pas fait pour les chiens.

        Argutie.



Cf multiples exemples au-dessus.

Et pour t'en donner un de plus, le code suivant est-il fiable, Ô Grand
Dieu ?

int write(char *file, char *data); // Issu d'une bibliothèque d'une
autre équipe de dev

void foo() {
write("/tmp/bar.txt", "Hello World !");
}



Code non conforme (et qui ne compilera pas sauf à bricoler la libc).
Par ailleurs, je t'ai dit beaucoup plus haut que l'hygiène du
développeur C était de récupérer toutes les valeurs retournées par
une fonction. La détection des erreurs est donc automatisable.
Tu essaies juste de noyer le poisson en prétendant qu'en jouant à
l'apprenti sorcier et en ne se souciant pas d'une valeur retournée,
il pourrait arriver quelque chose. En fait, on n'en sait rien, mais
l'erreur est de ton cru puisque tu ignores une valeur retournée.

Répond à la question ci-dessus, je te donne les détails après ta
réponse



Pas besoin de donner des détails. Tu es convaincu d'avoir raison

<EOT>

JKB

--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse...
=> http://grincheux.de-charybde-en-scylla.fr
Avatar
Aeris Imirhil
On 22 juin, 15:24, JKB wrote:
        Ça, mon grand, c'est spécifié dans le prototype et l'interface.



Gné ?
C'est quoi une interface en C ?

        Je suis désolé, mais je coupe ton blabla totalement i nintéressant.
        Je maintiens que tu n'as pas besoin de savoir comment est fichue une
        fonction à partir du moment où tu connais son interfa ce.



C'est quoi son « interface » ? Et je la trouve où ?

        Te rends-tu compte que ton argument est parfaitement idio te ? Si la
        doc est mauvaise, il est _normal_ que le code utilisant l adite
        bibliothèque soit buggué.



Pas en Java en tout cas !

Et alors ? La seule différence dans ce cas
        est que le compilo Java va gueuler, mais ce n'est pas pou r cela que
        ton code sera bon.



Correct pas forcément. Fiable si.

Et c'est sans compter
        que le throw de la signature est peut-être un résidu qui ne sert
        plus. Tu n'as _aucun_ moyen de le savoir.



Il vaut mieux traiter une erreur qui n'arrivera jamais que de ne pas
en traiter une qui arrivera…

> « void foo(…) throws FileNotFoundException, IOException » contien t en
> elle-même toutes les infos nécessaires à un code fiable, y compri s les
> cas d'erreur à traiter, quelque soit l'état de sa doc (même fauss e,
> inexistante ou incomplète) ou la disponibilité de son code.

        Non, parce que tu es _obligé_ de faire confiance à ce tte ligne qui
        peut comporter des choses amusantes voire totalement faus ses.



Peu importe, le but étant que toutes les erreurs qui peuvent
apparaître (fictives ou non) soient obligatoirement traitées.
Que le développeur lève trop d'erreur est un autre soucis, qu'on
trouve également en C.

> Non, de sa plage de valeur de retour admissible aussi.
> Si elle peut renvoyer 0 et -1, je n'ai pas le même code à écrire que
> si elle renvoie 0, -1 (ERROR_FILE) et -2 (ERROR_IO).

        Par prototype, j'entendais prototype _et_ interface. Ne f ais pas
        semblant de ne pas avoir compris.



C'est quoi « l'interface » dont tu nous parles depuis tout à l'heure  ?
C'est la doc ? Ce que te dit le dev de la fonction ?
Et si je n'ai ni l'un ni l'autre sous la main ?
S'il y a oublié de te signaler des cas qu'il traite quand même dans
son code ?
On est parti du principe qu'on avait de mauvais développeurs je te
rappelle…

        Arrête de te raccrocher aux branches, ça commence à se voir. Tu
        _dois_ connaître l'interface d'une fonction avant de l' utiliser.
        Enfin, c'est préférable.



Je la trouve où cette interface ?
Et « ce qu'elle fait » est totalement différente de « ce qu'elle n' est
pas sensé faire »
On a rarement une spec de ce que l'application ne doit pas gérer ou
des cas dégradés techniques…

        Non. Je te rappelle que tu prétendais qu'en C, on pouva it rater une
        erreur. Je viens de te démontrer que c'est faux (que ce soit avec
        des switchs ou avec des if/else).



Certes, mais dans ce cas tu perds en granularité.
En Java j'ai la certitude de tout catcher, sans perdre la possibilité
de traiter type d'exception par type d'exception.

        Je ne vois pas comment tu peux en oublier sachant que tu gères
        l'erreur à chaque appel (et de façon automatique avec une macro).



Cf ci-dessus.
Je fais comment avec ta macro pour traiter différemment l'absence de
fichier et le crash disque, et pour en avertir différemment
l'utilisateur ?

        Non, d'autant qu'il n'y a pas de méthode en C.



C'est petit ça…
Fonction si tu préfères…

        Mais bien sûr que si. Je ne t'ai pas donné le contenu de la macro en
        question. La macro traite les erreurs dans un switch et u ne fois
        l'erreur traitée, elle libère les ressources en renda nt la main à
        l'appelant. Elle fait exactement ce qu'il faut pour chacu ne des erreurs.



Et donc tu as autant de macro que de fonctions ?
Et ben il doit être joli ton code…

/* Gros Bloated de Macro */

void JKBFunction(…) {
CHECK_FOO(foo(), …);
CHECK_BAR(bar(), …);
CHECK_FOO_BAR(fooBar(), …);
}

>> > Les 2 codes sont à modifier en cas de correction de « bar  », sauf que

        Et tu te retrouves _aussi_ à gérer des erreurs qui n' existent plus
        parce que le type à laissé un throws bizarre dans le fichier.
        Merci, j'ai donné.



Vaut mieux en traiter trop que pas assez…
Je préfère que le mec me déclare une « PerceuseException » sur un e
Fraiseuse.
Au moins dans tous les cas de plantage j'arrêterais mon moteur…

        Et de le traiter en aveugle ou presque. C'est bien. On a une doc
        fausse, un code qui ne compile pas, puis on rajoute un ge stionnaire
        d'exception parce que le compilo te le demande... Et tu n e trouves
        pas ça aberrant ou casse-gueule ?



Moins casse-gueule que de me fier à ce que me raconte une doc
(rarement mise à jour ou complète) ou un développeur, d'autant plus
qu'on est parti du prédicat « les développeurs font n'importe quoi  »

        Je te rappelle (parce que tu coupes tellement qu'on n'arr ive plus à
        suivre) que le problème initial était de savoir si le s valeurs de
        retour étaient récupérées ou non. Je prétends q u'avec quelques
        macros bien senties tu peux t'en assurer. Il n'était pa s question
        initialement de savoir comment elles étaient traitées .



Je te rappelle que le sujet initial est de savoir qui d'un code en C
ou d'un code en Java est efficace pour être tolérant aux fautes, en
présence de développeurs incompétents.


        Il y a une doc. C'est l'hypothèse de base. De toute fa çon, même avec
        Java, je REFUSE de coder un truc lorsqu'un appel de fonct ion ne
        réagit pas comme cela est expliqué dans la DOC.



Tu as des devs tout pourris dans ton équipe…
Estime-toi déjà heureux d'avoir une doc…

Moi, mon truc, c'est
        le calcul. Et si une fonction est censée tourner avec u n integer*4,
        que c'est marqué dans la doc, je suppose que c'est vrai .



Tu supposes !
Mais s'il te retourne 5*i, ton soft n'est pas sécuritaire et ta
fraiseuse continuera à usiner avec le moteur de coupe arrété…

        Par ailleurs, si la doc ne correspond pas à l'interface réelle de la
        fonction, il y a de fortes chances que l'intérieur de l a fonction
        elle-même soit légèrement différente, ce qui impl ique non seulement
        d'autres erreurs à traiter, mais aussi des fonctionnali tés
        différentes.



Pour les fonctionnalités différentes, les tests U sont là pour les
éviter.
Pour les erreurs à traiter, le compilo est là pour s'assurer qu'aucune
ne sera raté !

Bref, mon expérience me dit que lorsqu'un truc n'est
        pas conforme à la doc, il vaut mieux ne pas l'utiliser.



Moi mon expérience me dit qu'il faut livrer le client à la fin.
Et que « Oui mais l'autre équipe de dev ne m'a pas livré une doc
correcte alors que le code l'est » n'est pas un argument recevable,
d'autant plus quand l'autre équipe ne dépend même pas de ta boîte.

        Non, tout le monde avait compris (sauf toi visiblement), que
        j'entendais pas prototype, prototype _et_ interface.



Donc pour chaque relecture de code, t'as la doc de toutes les méthodes
utilisées sous la main ?
Et tu vérifies que le code des libs que tu utilises est conforme à la
doc fournie ?
Tu passes ta vie à faire de la relecture de code ?

Et en gros tu ne fais pas la relecture du code de ton équipe mais plus
celle du code des autres ?

        Et ? La doc n'est pas fait pour les chiens.



Se reposer sur la doc est une hérésie.
Le code est la seule chose réelle avec laquelle tu intéragis, pas une
pseudo-vision du monde dépendant de la compétence, de la motivation et
du temps disponible.

> int write(char *file, char *data); // Issu d'une bibliothèque d'une
> autre équipe de dev

> void foo() {
>     write("/tmp/bar.txt", "Hello World !");
> }

        Code non conforme (et qui ne compilera pas sauf à brico ler la libc).



Pourquoi code non conforme ?
Je ne vois aucune justification…

        Par ailleurs, je t'ai dit beaucoup plus haut que l'hygi ène du
        développeur C était de récupérer toutes les valeu rs retournées par
        une fonction.



Prend ce code si tu préfères…

void foo() {
    int t = write("/tmp/bar.txt", "Hello World !");
}

J'attend toujours une réponse : ce code est-il fiable ou non ?
Et surtout pour quelle raison ?
Avatar
NiKo
Le 23/06/2011 16:02, Toxico Nimbus a écrit :

Euh ! Tu sais qu'on est aujourd'hui le 22 juin et non le 23 ?

--
Le mode sans échec de Windows est la preuve que son
mode normal est un échec !

SONY : It only does everything ... until we remove !
PS3 Firmware update 3.21 :
The first software update which downgrade !