1

Zerosquare a souhaité poursuivre une discussion dérivée dans un nouveau sujet. La discussion initiale a eu lieu dans le sujet topics/61689-jeu-videz-votre-presse-papier/997#post-29886 tandis que la discussion dérivée continue dans le sujet topics/187284-variables-globales-singleton-ou-parametres où les messages en rapport ont été copiés.
avatar
Ben, bouh, quoi :D

2

./29863 : est-ce bien le même Folco qui se pose des questions angoissées sur le meilleur style de code à adopter, tout ça ? grin
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

3

Oué ben parles-en, tu me fais angoisser avec ton "les vars globales, c'est mal" et "les singleton, c'est mal" grin
On fait comment pour un jeu, mettons le renderer principal t'en fais quoi ?
En soi, c'est global à l'appli, donc ça pourrait être une var globale mais c'est pas bien
On peut faire le faux-cul avec un singleton et un simple getter, mais c'est carrément hypocrite
Passer le renderer à chaque fonction du programme n'est pas une solution

Alors, c'est quoi la bonne façon de faire ? tongue

4

Même si un singleton te semble hypocrite, cela me semble beaucoup mieux. Les variables globales t'interdisent pas mal de choses comme de faire facilement des tests unitaires ou de réutiliser le code (bon, ça peut être secondaire si le code est vraiment spécifique).
avatar
<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant

5

Client-serveur multi-threadé massivement parallèle avec zero copy message passing.

Comme ça.

Carrément.

6

J'ai commencé un hello world comme ça, je compte bien le terminer un jour !

Flanker -> ok, merci. C'esdt le genre d'expérience que j'ai pas smile

7

Folco (./29866) :
Oué ben parles-en, tu me fais angoisser avec ton "les vars globales, c'est mal" et "les singleton, c'est mal" grin
Je ne me souviens pas avoir dit ça, et ce n'est pas ce que je pense, tu dois me confondre avec quelqu'un d'autre smile

(enfin je n'encourage pas l'abus de variables globales non plus, on est d'accord ^^)
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

8

(cela dit, il faut toujours se méfier des « il ne faut jamais » : si une mauvaise pratique permet de diviser par 10 ton code tout en l'accélérant, peut-être qu'elle n'est pas si mauvaise que ça dans un cas précis ^^)
avatar
<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant

9

(c'esdt vrai aussi, merci pour cette nuance hehe)

10

Perso je ne vois pas la différence entre une variable globale et un singleton, les conséquences me semblent être les mêmes à tout point de vue. J'aurais tendance à les éviter dès qu'ils exposent un service qui a des effets de bord, pour les raisons de tests que Flan évoque.
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

11

(je voyais un singleton comme une classe qu'on instance généralement une seule fois ; me trompé-je ?)
avatar
<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant

12

(non, pour moi c'est ça ; par rapport aux variables globales, un singleton avec des getters/setters de singleton est plus puissant, ils peut par exemple inclure des mécanismes de synchronisation pour éviter les race conditions. Et puis du point de vue encapsulation, c'est plus propre aussi.)
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

13

C'est pas seulement ça, si vous parlez du pattern "singleton" ça veut généralement aussi dire que cette classe expose de façon globale (via une méthode statique par exemple) un accesseur qui permet d'obtenir cette instance unique depuis n'importe où, si besoin en l'initialisant. Du coup ça a exactement les mêmes soucis de couplage fort qu'une variable globale et c'est tout autant impossible à injecter pour des tests. À moins de supporter une sorte de "mode test" au niveau du singleton, mais ça ne règle pas le problème de couplage et ça veut aussi dire polluer le code de son singleton à cause des tests donc c'est pas top comme solution.
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

14

Alors quelle solution propre adopter pour le cas de variables assez uniques, genre le handle de la fenêtre principale de ton programme, auquel beaucoup d'endroits du code ont légitimement besoin d'accéder ?
Une variable statique dans un source, avec à côté des fonctions pour l'initialiser et y accéder ? Pour moi c'est pareil, m'enfinça se présente différemment ^^

15

En fait je crois que je ne sais jamais si tu demandes une solution ou un avis. Comme souvent, ici c'est surtout une question de goût, la solution que tu proposes fonctionne et c'en est une parmi plein d'autres ^^ Si tu veux discuter de goûts et de couleur en revanche, moi j'aime bien ce qui est explicite y compris pour les dépendances, donc si une fonction a besoin d'accéder à une variable je lui passe en paramètre. Ça peut vouloir dire que beaucoup de fonctions vont avoir cette variable assez unique dont tu parles comme paramètre, et je trouve que c'est une bonne chose de ne pas le cacher en la remplaçant par une variable globale ou un singleton auquel tout le monde pourra magiquement accéder sans que ça se voit dans les signatures.
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

16

Zeph (./29878) :
moi j'aime bien ce qui est explicite y compris pour les dépendances
epee

(et je déteste encore plus quand même un IDE est incapable de savoir d'où vient un élément)
avatar
<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant

17

Zeph -> ben des solutions qui marchent, je viens d'en proposer 4 (var globale, var statique, singleton, et paramètre un peu partour).
C'est donc un avis que je demandais, et Flanker et toi venez d'être parfaitement clair à ce sujet. smile

J'ai juste un blocage psychologique très fort avec une variable qui va être passé à 50 fonctions en paramètre, donc 30 fois inutilement : question perf, c'est l'horreur grin

M'enfin, c'est oujours un peu le cas avec la programmation structurée. Merci beaucoup pour votre avis top

18

Folco (./29880) :
J'ai juste un blocage psychologique très fort avec une variable qui va être passé à 50 fonctions en paramètre, donc 30 fois inutilement : question perf, c'est l'horreur grin
Honnêtement je doute que l'impact au niveau perfs soit sensible, surtout sur une machine récente smile

Je trouve beaucoup plus gênant le fait que ça rende le code plus verbeux, donc moins lisible. Quand il s'agit de valeurs constantes et uniques (comme le handle de la fenêtre principale), perso je préfère utiliser une variable globale (ou un getter dans un singleton).
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

19

Zerosquare (./29881) :
que ça rende le code plus verbeux, donc moins lisible
Je ne suis vraiment pas d'accord avec ton implication. Il y a beaucoup de cas où rendre le code plus verbeux peut améliorer la lisibilité, et je fais entrer la question de Folco dans ceux-ci. Sinon tu pourrais aussi inliner toutes les constantes, variables et fonctions utilisées une seule fois, faire disparaître tous les types dans les langages qui le supportent (cf. discussion sur l'inférence il n'y a pas longtemps), ou je ne sais quelle autre réduction de code qui te ferait gagner quelques caractères mais à mon avis perdre beaucoup en lisibilité.
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

20

Oui je me suis peut-être mal exprimé smile

Inliner une constante nommée rend le code plus compact mais moins compréhensible, on est d'accord.

Mais ajouter un paramètre constant à plein d'appels de fonction, de mon point de vue :
- ça n'apporte aucune information utile
- ça introduit de la duplication, avec le risque de se planter (et de ne pas le voir, parce qu'on est habitué à ne plus regarder le paramètre constant)
- ça masque le fait que l'argument est constant, donc ça rend la revue du code de la fonction plus complexe pour rien
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

21

Justement, je trouve que :

- Ça apporte comme information que cette fonction dépend de cette variable. On le voit apparaître de façon explicite dans sa signature, sans avoir besoin de lire le code pour se rendre compte qu'il contient une référence statique vers un singleton ou une variable globale. Ça veut dire par exemple que si je veux tester unitairement cette fonction je ne peux pas oublier de fournir un mock pour cette variable.
- C'est une bonne duplication je trouve : si on se rend compte que cette variable est passée en paramètre à 75 fonctions, peut-être que ça traduit un autre souci dans le code et je préfère m'en rendre compte tôt. Ça rejoint un peu le point précédent et je pense qu'il va être difficile de faire des généralités ici, mais je pense que dans la majorité des cas ça traduit un couplage trop fort entre un type et tout le reste du code, là où un sous-ensemble de ce type pourrait être suffisant. Si par facilité on peut accéder à une instance globale depuis n'importe où, c'est très difficile de repérer cette erreur (et de ne pas faire grossir cette instance en lui ajoutant des fonctionnalités petit à petit jusqu'à ce que ça devienne un monstre impossible à remplacer ni tester facilement).
- Comme Folco fait du C++ il peut utiliser "const", ou "val", ou ne pas mettre "mut", ou je ne sais quelle variante dans tout plein de langages qui possèdent justement la bonne fonctionnalité pour ce genre de cas ^^
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

22

Ok, vos arguments se tiennent tous les deux, bien sûr, vous en êtes pas à votre coup d'essai et on sent les expériences qui dictent vos propos ^^

Alors, voyons mon cas. j'utilise la SDL pour faire un jeu. Cette lib utilise un SDL_Renderer pour faire tout ce qui est dessin dans la fenêtre principale. Tous les objets qui dessinent/se font dessiner doivent avoir un pointeur vers ce SDL_Renderer*.

Aucun objet, image, sprite, texte, whatever, ne se dessine en-dehors de ce SDL_Renderer, constant du début à la fin de l'exécution du programme. Tout le monde a donc besoin de ce SDL_Renderer* dans mon programme.

Je code en C++, j'ai choisi le singleton, qui est pour moi la variable globale C/asm en équivalent C++ élégant.
Squelette de la classe : http://www.mirari.fr/VrWf

Concrètement, dans ce cas-là, serait-il mieux de passer cette variable à la moitié des fonctions du code ? Ou alors, si je dois passer cette variable un peu partout, n'est-ce pas symptomatique d'un code bordélique (la réponse peut être "oui", ça me gêne pas grin)

Parce que question lecture, "tapage" de code et efficacité machine, je trouve ça overkill de me ballader cette variable un à tous les niveaux du jeu, même là où ça n'a rien à faire (gamestates etc...)

23

Passer un pointeur à chaque fonction augmente la taille de la pile de 4 octets par ajout (si on oublie un instant les possibles optimisations du compilo, dans le cas où tu ne fais que forward le pointeur par exemple), je suis pas certain que ce soit un gros problème, mais imo dans ce genre de cas avoir un singleton fait plus de sense.

Je suis en train de faire un renderer 3D pour les asset de Wow (ça se voit sur mes précédents posts ici, non? grin), et de mon côté j'ai tout simplement choisi de stocker GxContext (l'équivalent de ton SDL_Renderer*) dans toutes les classes qui décrivent de la géométrie ou des sources de lumière.

Ça n'empêche pas GxContext d'être unique: son cycle de vie est contrôlé par le programme. Si j'ai besoin de plusieurs surfaces de rendu, je définis de nouvelles textures pour le depth stencil, etc, et je dessine dedans.

Du coup à mon sens, avoir un singleton ici est la chose la plus logique à faire; et dans la foulée, je forcerai sa création au démarrage du programme. Je réalise que ce n'est pas ce que j'ai fait, mais mon programme ne sert pas qu'à visualiser de la géométrie, c'est aussi un outil pour le datamining, et le rendu 3D n'est qu'un bonus grin

Petite note: DirectX n'apprécie pas qu'on envoie des commandes depuis plusieurs threads (à juste titre); je ne connais pas le positionnement d'OpenGL et/ou de la SDL à ce sujet mais quand tu commenceras à devoir toucher au threading, garde ça en mémoire wink

(Je ne sais même pas si c'est autorisé d'avoir plusieurs pipelines de rendu, quelle que soit l'API utilisée; j'ai toujours recyclé un unique pipeline ...)

Fork?

24

Zeph > tes arguments sont cohérents, mais je reste pas convaincu. Je pense que toi et moi n'avons pas les mêmes priorités (et qu'on ne bosse pas sur le même genre de projets, accessoirement).

Folco > aucune des méthodes évoquées n'est mauvaise en soi. Tant que tu fais un choix réfléchi et que tu t'y tiens, c'est déjà très bien. Et tu as le droit d'avoir tes préférences personnelles, surtout quand tu es le seul à maintenir ton code. À vouloir faire trop bien, on finit par ne rien faire ^^
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

25

À mon avis, le principal avantage du singleton par rapport à une variable globale est qu'il y a moins à changer si on a finalement besoin de plusieurs instances (on a déjà l'objet, il "suffit" de le rajouter en paramètre un peu partout, alors que si on avait des variables globales, il faut en plus créer l'objet qui les encapsule), le principal inconvénient est que ça rend le code plus compliqué et plus lent.

Sinon, une autre méthode serait d'avoir un objet application qui a toutes ces variables en variables d'instance et duquel pratiquement toutes tes fonctions sont des méthodes. Bref, un seul singleton, où tu peux éventuellement te passer du pattern singleton, il suffit de le construire dans main et rien d'autre n'a à obtenir une instance. Mais c'est pratique surtout si le code était procédural à 99%, sinon, ça va entrer en conflit avec les "vrais" objets. (C'est la méthode à choisir si on a du code purement procédural avec des variables globales et veut le rendre réentrant.)
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

26

J'y ai déjà pensé, j'ai testé ce concept. Tu fais une classe Game qui contient tout le reste du jeu, dont ces fameuses variables globales qui en sont alors des membres.

27

Zerosquare (./24) :
Zeph > tes arguments sont cohérents, mais je reste pas convaincu. Je pense que toi et moi n'avons pas les mêmes priorités (et qu'on ne bosse pas sur le même genre de projets, accessoirement).
Oui bien sûr, c'est pour ça que j'essaie de ne pas oublier de mettre des "je trouve" et des "à mon avis" tous les 3 mots quand j'écris ce genre de post ^^

Folco : une autre question que tu peux te poser, c'est "est-ce que ce renderer est réellement unique dans tous les cas d'utilisation auxquels tu peux penser" ? On pourrait imaginer un jour que tu fasses une application qui fasse apparaître plusieurs fenêtres simultanément et qu'ils faille dessiner dans chacune d'entre elle. Dans cette situation avoir une variable globale ou un singleton serait peu pratique, tu serais obligé d'ajouter des méthodes pour remplacer ce singleton à la volée et tu te retrouverais avec un horrible tas de méthodes basées sur des effets de bord qui rendraient ton code très difficile à lire et impossible à rendre multi-thread.

À l'inverse si tu sais que c'est un cas d'utilisation que tu ne rencontreras jamais alors peut-être qu'avoir une variable globale ou un singleton sera une solution viable pour toi smile (et ça me coute beaucoup d'écrire ça, à titre perso c'est niet sans exception possible grin)
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

28

Ok, merci ! Intéressant en effet. smile

29

Par contre, je ne suis pas totalement d'accord pour dire que c'est une question de goût.
Même si c'est en partie vraie, il y a tout de même des arguments assez objectifs dans un sens comme dans l'autre qui ont plus ou moins d'importance suivant le contexte (par exemple les performances ou le besoin de maintenir le code sur une grande période).
avatar
<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant

30

Zeph (./27) :
Folco : une autre question que tu peux te poser, c'est "est-ce que ce renderer est réellement unique dans tous les cas d'utilisation auxquels tu peux penser" ? On pourrait imaginer un jour que tu fasses une application qui fasse apparaître plusieurs fenêtres simultanément et qu'ils faille dessiner dans chacune d'entre elle. Dans cette situation avoir une variable globale ou un singleton serait peu pratique, tu serais obligé d'ajouter des méthodes pour remplacer ce singleton à la volée et tu te retrouverais avec un horrible tas de méthodes basées sur des effets de bord qui rendraient ton code très difficile à lire et impossible à rendre multi-thread.

À l'inverse si tu sais que c'est un cas d'utilisation que tu ne rencontreras jamais alors peut-être qu'avoir une variable globale ou un singleton sera une solution viable pour toi smile (et ça me coute beaucoup d'écrire ça, à titre perso c'est niet sans exception possible grin)
Mais comme j'ai déjà dit, un singleton sera quand-même plus facile à adapter pour ça qu'un paquet de variables globales, à moins qu'on ne puisse utiliser l'astuce de l'objet application.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité