[Langage] Jade
| Mod |
Posté le 11 Fév 2009 à 18:12
|
|
![]() Messages : 4954 GCPoints : 2100823 |
Mise à jour : Petit à petit, j'avance dans la structuration des données utilisées pour représenter l'orientation objet dans le compilateur. Ca reste relativement casse-tête, mais je pense être sur la bonne voie. La création des classes et méthodes commence vaguement à prendre forme, et semble assez efficace, bien que j'ai du code redondant dans chaque analyseur de structure (comme je le disais plus haut, l'analyseur syntaxique de classe doit contenir le code pour les classes, structures, méthodes, énumérations... Celui des modules pour les classes, énumérations, fonctions... etc). Difficile de dire quand j'aurais achevé cette transformation monstrueuse, mais le blocage qui subsistait depuis quelques jours commence à disparaître. Et ça, c'est bon signe :). |
|
| Darktib |
Posté le 12 Fév 2009 à 18:46
|
|
![]() Messages : 4017 GCPoints : 347288 |
Ca avance bien apparement. a quoi ressemble actuellement une classe sous Jade ? | |
| Mod |
Posté le 12 Fév 2009 à 19:17
|
|
![]() Messages : 4954 GCPoints : 2100823 |
Ca reste très simple, dans la droite de lignée de ce que cela aurait pu être sous Dark Basic. Tout simplement : Code : class MyClass ... endclass Pour l'héritage : Code : class MyClass as MyParentClass ... endclass Pour les méthodes, constructeur et destructeur (par défaut c'est du privé) : Code : class MyClass
public function MyMethod(a,b)
...
endfunction
public constructor()
...
endconstructor
public destructor()
...
enddestructor
endclassPour les propriétés (pareil, par défaut, c'est du privé) Code : class MyClass
private a as integer
private b as float
public property A as integer
get
...
endget
set
...
endset
endproperty
endclassEn gros, tout est nommé explicitement au lieu d'utiliser des accolades, des crochets, et autres caractères spéciaux qui font peur. |
|
| Darktib |
Posté le 12 Fév 2009 à 20:43
|
|
![]() Messages : 4017 GCPoints : 347288 |
Le systeme des get/set est plutot bien pensé, ca facilitera la tache. Sinon sera t il possible de faire Code : class MaClasse
public:
...
private:
...
endclass
|
|
| Mod |
Posté le 12 Fév 2009 à 21:09
|
|
![]() Messages : 4954 GCPoints : 2100823 |
Non, ce ne sera pas possible. Cela peut paraître contraignant sur le coup, mais à l'usage, c'est bien plus pratique d'effectuer cela par un marqueur de portée avant chaque méthode/propriété. En pratique, l'orienté objet de JadeBasic est d'ailleurs globalement similaire à celui du C#, et notamment sur ce point là. Typiquement, lorsque l'on créera des propriétés, on effectuera ce type d'ordonnancement pour simplifier la lecture et l'organisation du code : Code : class MyClass
private a as integer
public property A as integer
get
endget a
set
a = value
endset
endproperty
private b as float
public property B as float
get
endget b
set
b = value
endset
endproperty
endclassCela serait rapidement ingérable que de passer par un private:/public: à chaque fois. Maintenant que j'y pense, l'utilisation de la syntaxe du couple property/endproperty est encore sujet à caution, j'hésite entre celui-ci et d'autres termes, notamment accessor/endaccessor, qui peut sembler plus précis. |
|
| Darktib |
Posté le 12 Fév 2009 à 21:58
|
|
![]() Messages : 4017 GCPoints : 347288 |
Je pense que 'property' est plus adapté, vu que tu a 'set' qui lui n'est pas un accesseur... | |
| Mod |
Posté le 14 Fév 2009 à 21:18
|
|
![]() Messages : 4954 GCPoints : 2100823 |
Citation :
Oui, quand je parlais de plus précis je pensais au getter, justement. Avec le vocabulaire associé pour le setter. Manque de précision de ma part, pour le coup :s. Pour ce qui est de l'avancée : Après mûre réflexion, je commence à me demander si je ne vais pas laisser de côté une grosse partie de l'orienté objet que je comptais jusqu'à présent implémenter. A dire vrai, je viens en fait d'achever la gestion des schémas imbriqués de classes, modules, etc, avec la transmission des types générés entre les différentes entités de code (les private/public/protected n'étant pas encore transmis cela dit, mais la difficulté n'était pas vraiment là). Le fait est que maintenant que j'en suis arrivé là, je me rend compte qu'outre placer sur le terrain la nécessité d'avoir un compilateur devant prendre en compte une multiplicité de cas assez importante (et c'est un euphémisme), cela provoquait aussi en parallèle une véritable explosion en termes de complexité de code pour l'utilisateur, ce qui passe totalement à côté de mon objectif de créer un langage simple à utiliser dans sa totalité, exploitable au mieux dès que l'on en a saisi les concepts. Par là, je pense par exemple à la gestion des public/private au niveau des classes ou structure imbriquées qui devient très rapidement un casse-tête si on n'y prend pas garde. En gros, c'est toute la gestion "en profondeur" des structures de code qui pourrait passer totalement à la trappe. De cette manière, je pourrais me permettre de me concentrer au maximum la gestion linéaire des structures de code (notamment l'héritage et le polymorphisme). En pratique ça ne changerait pas forcément grand chose, au lieu d'avoir des imbrications, on aurait des noms de classes, de structures, etc, totalement différents. Je vais encore y réfléchir, sans doute très longuement... |
|
| Mod |
Posté le 16 Fév 2009 à 22:03
|
|
![]() Messages : 4954 GCPoints : 2100823 |
Finalement il s'est avéré que le code mis en place jusqu'à présent pour l'imbrication des structures de code n'était pas si viable que ça. Ce qui fut une bonne occasion pour continuer de réfléchir sur la suite à donner à l'orientation objet, notamment par rapport au problème dont je parlais la dernière fois. Et après mûre réfléxion, c'est fait : l'imbrication des structures de code ne sera pas faisable en JadeBasic. La nouvelle structuration que j'ai commencé à mettre en place (reprise à zéro n°3) pourrait être un support un peu plus convenable, mais je ne pense pas faire de retour en arrière sur ce point là. Bon, bien sûr, le fait de ne pas avoir à gérer les imbrications de structures de code simplifie une grosse partie du travail à effectuer, me permettabt de le concentrer sur la gestion linéaire des structures. De ce point de vue là, le compilateur JadeBasic devrait assurement être très performant. Un exemple relativement simple tient au fait que le compilateur est capable de reconnaître les structures dans le code, et d'extrapoler leur utilisation antérieure. En termes plus clairs, on a par exemple ceci en Dark Basic : Code : type test1 a as test2 endtype type test2 a as integer endtype Un code de ce genre provoque une erreur, car test2 est déclaré après test1. C'est d'ailleurs la même chose en C et C++, si on déclare une structure de code de ce genre sans avoir créé de header, on obtiendra rien de plus qu'un crash : Code : struct test1
{
test2 a;
};
struct test2
{
int a
};Là où je veux en venir, c'est que le compilateur JadeBasic saura au contraire analyser un code de ce genre sans le moindre soucis : Code : struct test1 a as test2 endstruct struct test2 a as integer endstruct Cette capacité d'analyse est certes très intéressante (surtout pour un débutant qui n'aura cure de l'ordre de déclaration des structures), mais on pourrait imaginer qu'elle cause des soucis. Par exemple ce code : Code : struct test1 a as test2 endstruct struct test2 a as test1 endstruct Si le compilateur connaît d'avance toutes les structures, celle-ci n'est syntaxiquement pas une erreur, même si on comprends aisément que cette inclusion simultané ne peut avoir lieu. Or, le compilateur est capable de détecter ce genre d'imbrication infinie, et vous fera savoir nettement que c'est une grosse bourde, à coups de "fatal error". Pour le pourquoi du "fatal" (petite remarque pour aller juste un peu plus en profondeur), il suffit de résumer le fonctionnement du compilateur: Analyse lexicale : on récupère les différents symboles du code source. Analyse des structures de codes : on créé les fonctions, classes, méthodes, etc. Analyse des clés de type : en clair, les types n'existe pas encore, il sont purement virtuels à ce moment là de la compilation, et référencés par une clé (tout simplement leur nom) pouvant lier à une classe, une structure, un type standard... Dans cette étape, on vérifie que toutes les clés utilisées sont des clés référencées. Analyse des types : ici, on génère "simplement" les types à partir des clés, en vérifiant qu'il est possible de les créer. C'est ici qu'est généré l'erreur fatale, car vient ensuite : Etablissement du typage : on lie toutes les clés et leurs types, c'est là que les structures de code prennent leur relief, puisqu'en les liant à des types, on leur donne une certaine taille en mémoire, c'est le premier pas vers la génération de code. On peut alors comprendre que si cette étape-ci n'est pas remplie, on pourra difficilement aller plus loin, d'où l'erreur fatale. Je vais en profiter pour détailler les types d'erreurs pouvant être générés, ça servira lors de la disponibilité de la prochaine bêta publique : "Error" : erreur de compilation à cause du code. "Fatal error" : erreur fatale de compilation à cause du code soumis au compilateur. "Internal error" : des cas d'erreurs internes au compilateur, qui ne devraient normalement jamais apparaître. Ce sont des sécurités que j'ai placé au cas où pour signaler un bug majeur du compilateur. Voilà pour le blabla ^^. A part ces considérations, la remise en état des systèmes précédemment opérationnels avance plutôt bien. Je pense avoir tout rétablit d'ici la fin de la semaine. |
|
| Mod |
Posté le 18 Fév 2009 à 20:47
|
|
![]() Messages : 4954 GCPoints : 2100823 |
Toujours dans les développements. La restauration des fonctionnalités avance aussi bien que prévu, le compilateur est à nouveau capable de générer du code assembleur pour les variables et calculs standards. Les fonctions utilisateurs sont prises en compte et compilées correctement :). Autrement, j'ai commencé à réimplémenter la gestion des librairies externes... D'ici peu de temps, cela devrait être à nouveau fonctionnel, et surtout, utilisable pour compiler des exécutables autonomes. Pas grand chose à dire de plus pour le moment, ça va changer des gros pavés habituels :p. |
|
| Mod |
Posté le 20 Fév 2009 à 20:27
|
|
![]() Messages : 4954 GCPoints : 2100823 |
Ce fut long (et terriblement ennuyeux), mais ça y est, j'ai fini d'implémenter la nouvelle architecture du compilateur JadeBasic. Le compilateur est passé au tout objet, et ça facilite déjà assez bien la maintenance sur les structures de code complexe qui sont maintenant à gérer, telles que les classes. Ce que j'attendais surtout de cet achèvement, c'était de pouvoir à nouveau compiler du code JadeBasic en code machine. C'est chose faite, et ça rendra la réimplémentation des différentes fonctionnalités du langage bien plus intéressante que de tout faire via affichage du code Assembleur généré et de le faire tourner "de tête". J'en reviens donc enfin à la partie passionnante de la création de langage, ce qui devrait donner un coup de fouet au développement. |
|
| Mod |
Posté le 21 Fév 2009 à 18:08
|
|
![]() Messages : 4954 GCPoints : 2100823 |
Comme prévu (pour une fois), les choses avancent vite, et bien ! J'ai déjà pu réimplémenter ceci depuis hier : - do...loop - if...endif - if...else...endif Et même un petit peu d'innovation : il y a désormais un mot-clé "break" permettant de quitter les différentes boucles (pour le moment présentes) : - do...loop - while...endwhile - repeat...until Ce break est quand même un petit peu au-dessus du break bien connu du C, puisqu'il fonctionne comme celui du PHP. A savoir que l'on peut lui adjoindre une valeur indiquant le nombre de boucles que l'on souhaite quitter. Pas d'exemple pour le moment, mais vous verrez qu'à l'usage, c'est très pratique d'avoir ce genre de possibilité, cela évite de devoir ajoindre en supplément une variable pour quitter les deux d'un coup comme on doit le faire en C ou C++. Autre innovation : le if supporte (enfin) le "then" pour effectuer un test logique sur une seule ligne de code. Au final, ça ne fait pas grand chose vu comme ça, mais derrière, la façon dont ces différentes fonctionnalités sont possibles a été totalement révisée, et n'a plus grand chose à voir avec le précédent compilateur. Le fait d'avoir déjà travaillé dessus ayant tout de même grandement aidé. |
|
| Darktib |
Posté le 23 Fév 2009 à 21:37
|
|
![]() Messages : 4017 GCPoints : 347288 |
J'aime bien le concept du break [variable]. Est-ce que cette variable devra etre fixée dans le code ou pourra changer en fonction de l'execution du programme ? | |
| Mod |
Posté le 24 Fév 2009 à 10:39
|
|
![]() Messages : 4954 GCPoints : 2100823 |
C'est fixé dans le code par un nombre entier constant. Le code étant compilé, on ne pourrait pas déterminer où sauter en cours d'exécution. Un interpréteur saurait en revanche le faire, vu qu'il a un accès au code source en cours d'exécution. | |
| Mod |
Posté le 25 Fév 2009 à 22:48
|
|
![]() Messages : 4954 GCPoints : 2100823 |
De la même manière qu'il a été implémenté un motc-lé "break" pour se charger de quitter les différentes boucles, un mot-clé "continue" a été ajouté afin d'effectuer une reprise de boucle. Là encore, on fonctionne sur plusieurs niveaux à l'aide d'un argument spécifiant la boucle à continuer. Pas d'exemple non plus cette fois-ci, mais là encore, l'intérêt est bien présent. Ajout dont l'utilité sera un peu plus courante : "elseif". Pas vraiment besoin d'explications pour les programmeurs du coin ; pour les autres, il s'agit d'une structure de code qui effectue un nouveau test (il me semble que RPG Maker a un code d'évènement semblable) : Code : if a = 1 // code exécuté si a = 1 elseif a = 2 // code exécute si a = 2 elseif a = 3 // code exécuté si a = 3 else // code exécuté si aucun des cas précédents n'a été rencontré. endif Notez que le mot-clé "then" fonctionne tout aussi bien ici : Code : if a = 1 // code exécuté si a = 1 elseif a = 2 then // code exécuté si a = 2 Du côté des remises en état, les types structurés sont à nouveau opérationnels. Enfin, après plusieurs jours de tests, essais, et développements en tous genres, j'ai achevé l'implémentation d'un Garbage Collector à JadeBasic. Le principe d'un Garbage Collector est relativement simple : vous créez les objets dont vous avez besoin, le GC se charge de les supprimer quand il ne sont plus utiles dans aucun autre objet. C'est une capacité que l'on retrouve dans un certain nombre de langages comme le Java, le C#, le D, le Python, etc. Au niveau algorithmique, le Garbage Collectorde JadeBasic utilise globalement le même algorithme "Mark and Compact" que le C#. Ca m'aura pris trois bonnes journées de recherches, plus une de développement pour concrétiser tout cela. Bien entendu, avec si peu de temps, il y a une grande marge de progression en termes de performances. D'abord parce que c'est tout logiquement la première fois que je créé ce genre de programme, mais aussi parce que j'utilise du code C++ pas forcément le plus véloce/adapté possible (des vector, notamment). Reste aussi que le code C++ pourrait avantageusement être remplacé par du code assembleur. Vraisemblablement plus rapide, même avec les optimisations d'activées, et surtout bien moins pénible à coder, le nombre de transtypages pour jouer sur les pointeurs étant tout simplement monstrueux (ce qui rend le code vraiment désagréable). Toutefois, même si ce Garbage Collector est déjà opérationnel, il reste un essai de développement plus qu'un choix définitif. Il y a du pour et du contre à l'utilisation d'un GC, je reste donc dans l'incertitude. Cela devrait normalement se dissiper avec le temps, vers l'un ou l'autre des "camps". Notez tout de même que si le Garbage Collector devait devenir définitif, il resterait possible de créer des objets et de les détruire manuellement, tout simplement parce que le système ne sera pas forcément parfait dans la totalité des cas de développement possibles. Mais à ce moment là, on prend le risque d'avoir des fuites mémoire, au développeur d'en subir les conséquences ! Par rapport au pour et au contre, comme je le disais plus haut, j'ai longuement brassé le sujet, et au Garbage Collector, on peut associer les avantages suivants : - Allocations rapides (la mémoire étant déjà allouée au démarrage de l'application, pas besoin de malloc, qui peut être lent, on ne fait que piocher dans cette mémoire virtuelle) - Les pointeurs d'objets ne transparaissent pas au niveau du programmeur (Garbage Collector et pointeurs ne sont pas très compatibles, sachant que les objets sont déplacés dynamiquement en mémoire selon les besoins). - Pas de fuite mémoire (c'est le principal intérêt d'un Garbage Collector). - Résultat : programmes plus stable et sécurisés côté mémoire. Ce qui peut être un bon point pour un BASIC. Et les désavantages suivants : - Ralentissement lors des phases de collecte de la mémoire (ce qui peut poser problème dans des applications en temps réel comme les jeux, justement, ce qui est un gros bémol). - Collectes automatiques de mémoire difficilement prévisibles (je reviens dessus un peu après). - Rend inutile ou presque les destructeurs (appel incertain, cf ci-dessus). - Pas de gestion de pointeurs (si on aime, sinon c'est un avantage). - Prend paradoxalement de la mémoire supplémentaire pour supporter la représentation des objets (à ce niveau là, je pense toutefois avoir fait assez simple pour que la consommation reste limitée). - Nécessite une certaine réflexion pour réduire le nombre de collectes. - Consécutivement à la remarque ci-dessus : limiter le nombre d'objets temporaires. - Consécutivement au deux remarques ci-dessus : coder à la barbare est autant sanctionné qu'avec un langage sans Garbage Collector. Par rapport aux collectes automatiques, donc, je précise bien le mot "automatique". Il sera possible d'effectuer des collectes manuelles, et pour tout dire, ce serait même conseillé. Les collectes automatiques sont en effet déclenchées lorsqu'il n'y a plus du tout de mémoire de disponible, et à partir de là, le Garbage Collector va la brasser sur toute sa longueur pour récupérer les morceaux qui traînent, cela pouvant être assez long et source de micro-ralentissements gênants. L'intérêt de la collecte manuelle, c'est d'effectuer la collecte à intervalles réguliers. De cette manière, on travaille moins d'un coup, la charge est donc mieux répartie, et le ralentissement absent (du load balancinr, en gros). Ce problème de ralentissement pourrait toutefois être minime (et minimisé par l'amélioration du Garbage Collector), il faudra voir ça en production "réelle". Pour terminer, c'était déjà un fait établi depuis un certain temps, mais non cité explicitement pour l'instant : le passage des objets (et strucures) se fait uniquement par référence, tandis que le passage des variables appartenant à des types standards (entier, flottant, chaîne de caractères...) se fait uniquement par valeur. En pratique, c'est très confortable, et cela simplifie surtout énormément le travail de passage d'objets (pas de pointeurs dans tous les sens) et d'accès aux méthodes (pas de "->" qui embourbe le code). Voilà tout pour les derniers développement sur JadeBasic. Il y a fort à parier que le Garbage Collector fera encore parler de lui prochainement, peut-être à propos d'amélioriation, peut-être à propos de son retrait... Wait'n'see.
Dernière édition le 26 Fév 2009 à 10:33
|
|
| SEB |
Posté le 26 Fév 2009 à 09:42
|
|
![]() Messages : 554 GCPoints : 103313 |
Je trouve très franchement que le travail que tu fais est remarquable et extrêmement pratique et intéressant pour permettre un développement de jeu amateur de qualité. Etant un peu fana du code brut en c ou c++, je suis un peu anti simplification abusive. C'est pour cela que je ne suis pas trop pour le codage de jeu dans des langage à objet de haut niveau. Genre C# Java etc... en effet je trouve que si l'on commence par coder dans ce genre de langage on perd une sorte de 'conscience' permanente de ce que l'on écrit. Je m'explique : 1 on perd un peu la conscence de l'allocation mémoire (gràce au garbage collector) donc on a tendance à faire de l'allocation un peu barbare. 2 on ne pense pas en permanence qu'on trimbale des pointeurs et on a du mal à voir ou se trouve la copie et ou se trouve l'original. 3 On modifie des paramètres naturellement sans en être conscient non plus. (passage par référence) Pour moi, les langages haut niveau sont très bien pour faire des prototypes fonctionnels rapidement et simplement. Ou encore des outils d'accompagnement. Mais de gros projet super optimisés.. je demande encore à être surpris :) J'avais par contre une autre petite interrogation (bete je pense car la reponse est un peu evidente), le garbage collector natif au langage ne va pas poser de problemes avec l'allocations dans des librairies externes? (ok je sors XD) Sinon excellent boulot j'ai hate d'essayer ^^ :)
NextGine : 3D games engine
Nombre de lignes actuel : 77683 |
|
| Mod |
Posté le 26 Fév 2009 à 11:59
|
|
![]() Messages : 4954 GCPoints : 2100823 |
Mon avis plus brut sur la question du Garbage Collector, c'est que j'apprécie autant le fait de ne pas avoir à me soucier de la mémoire pour les langages en possédant un que je n'apprécie pas l'impression de ne pas avoir un contrôle absolu sur le cycle de vie de mes objets. J'était également plutôt porté sur le langage C, voire C++, à la base, et donc d'autant plus facilement attiré par le bas niveau. Cela dit, à la réflexion, je ne peux que constater que, en règle générale, le fait de devoir gérer la mémoire manuellement n'apporte rien en termes de codage. Une fois un objet créé, on doit le détruire à un moment où un autre, et il y a plus de chance de se tromper en le faisant à la main qu'en l'automatisant. Les variables locales, par exemple, fonctionnent de la même façon : on les déclare, et on ne se soucie pas de les détruite à la main : elle le sont automatiquement, à la fin de la portée locale. Cela semble-t-il pour autant étrange ? Ca n'est finalement pas très différent d'avoir un Garbage Collector, on créé ses objets, qui seront détruits automatiquement une fois devenus inutiles. A la limite, cela pourrait même être le comportement par défaut, plutôt que d'avoir à tout faire à la main. Citation :
De la même manière qu'un bon programmeur dans un langage sans Garbage Collector saura correctement manipuler la mémoire, sans fuite ou bug quelconque, un bon programmeur dans un langage avec GC saura créer de façon adéquate ses objets. Je tendrai même à dire qu'on y fait même plus attention dans un langage avec GC pour éviter justement de surcharger ce dernier. Citation :
Ca c'est un problème de programmation purement C++ (et issue d'une pensée de programmeur C++ ^^). C'est quelque chose que l'on ne retrouve que grâce à des abominations comme les copies implicites (avis personnel, mais c'est un point que je déteste particulièrement en C++, et qui a été mal pensé). Ce genre de problématique de copie/original, ça n'existe pas en JadeBasic. A moins de préciser très explicitement que l'on veut copier un objet, on ne travaille que sur l'original, et c'est l'original qui est systématiquement passé. Si on a besoin de faire une copie, alors on créé une méthode pour, ou un constructeur par recopie. C'est quelque chose que l'on retrouve en C#, et c'est extrêmement appréciable, en plus d'être plus logique que de faire des copies continuellement. J'ai déjà vu cela présenté comme une "lacune" de ce langage, alors que c'est une façon différente de faire à adopter (et bien souvent, car il était considéré que le C++ était la référence absolue des langages de programmation, ce qui est bien évidemment loin d'être le cas). Lorsque j'ai commencé à programmer en C#, j'étais justement un peu perdu de ce point de vue là, entre ce qui passait par copie et par référence. Ca peut paraître étrange quant on vient du monde du C/C++ de se dire que tout passe par référence, et que les objets ne sont jamais copiés, mais une fois que l'on y est habitué (c'est une autre manière de penser à acquérir), c'est infiniment plus confortable (même en excluant la question du Garbage Collector), et aussi plus rapide (pas de code superflu). Il suffit juste d'avoir de quoi comparer pour se rendre compte de la réalité. Ce n'est pas le C# ou le Java qui sont réellement de haut niveau sur ce point de vue du passage par référence des objets, c'est le C++ qui est tout simplement un noeud de complexité affolant (à mes yeux c'est donc plutôt le C++ qui a une complexité "abusive" ;). Le langage a été créé dans la continuité du C, et fait subir aux programmeurs son héritage de façon douloureuse, même si on ne s'en rend compte qu'une fois passé de l'autre côté du miroir. D'un point machine, et par là j'entends Assembleur, le passage le plus naturel et simple pour un objet se fait d'ailleurs par référence (encore que dans l'absolu, ce que l'on appelle passage par référence n'est rien d'autre qu'un passage par valeur). Citation :
La ça revient à ce que je disais plus haut : c'est une question de pensée et d'habitude. Citation :
Là, ça reste à déterminer entre langages comparables (C++ et D ?). Les langages RAD auxquels on peut faire référence comme le C# ou le Java tournent via des machines virtuelles, ce qui reste forcément plus lent qu'un langage compilé en code machine. J'ai lu une tonne de documentation sur la présence d'un Garbage Collector dans un langage et ses effets sur la vitesse d'exécution (car bien évidemment je ne souhaite pas faire de JadeBasic un langage lent), et à plusieurs reprises j'ai pu voir de bons arguments sur le fait qu'un langage à Garbage Collector peut être plus rapide, notamment celui-ci : http://www.digitalmars.com/d/2.0/garbage.html. Avec le temps, on voit d'ailleurs se développer un paquet de langages à GC : 1986 - Objective C, Eiffel 1987 - Perl 1990 - Python 1995 - Ruby, Java, JavaScript 1999 - D 2001 - C# Pour les plus connus. Il y a donc fort à parier qu'avec le temps, et l'augmentation continuelle de la puissance des ordinateurs, les langages du genre se développeront majoritairement. Et avec cela le perfectionnement des algorithmes de collecte, et donc de vitesse d'exécution. Citation fort judicieusement placée sur Wikipédia : Citation :
Citation :
Pas forcément si bête, je me suis posé la question justement de l'interfaçage entre librairies externes et Garbage Collector, mais dans la mesure ou la librairie est autonome et gère sa mémoire correctement, il n'y pas véritablement de soucis. Et merci pour le commentaire ^^. (Au passage j'ai remis en forme mon précédent message, semblerait que le copier-coller via Notepad ait fait des siennes avec le retour à la ligne). |
|
| SEB |
Posté le 26 Fév 2009 à 12:37
|
|
![]() Messages : 554 GCPoints : 103313 |
Il est évident que mon commentaire n'engage qu'un passionné de C/C++ comme moi et aussi peut-etre un peu d'un certain égoisme vis à vis du code que je produit. Comprennez par la que j'aime bien décider moi même de 'Quand' est-ce que je demande de la mémoire, 'Quand' est-ce que je la libere, de la même façon que de décider : Ici je passe mon paramètre par pointeur parce que je veux que ce soit une simple copie de pointeur mais également que le paramètre puisse être NULL. Par contre ici je le passe par référence parceque je veux que le passage soit léger mais je veux obligatoirement un objet existant. ainsi que la je ne veux pas de référence car utiliser une copie que je modifierais a mon gré sera d'autant plus efficace. En gros ce que j'aime dans le fait d'avoir plusieurs possibilité, c'est la possibilité de 'choisir' comment je veux que ça se passe dans les moindre détails. Mais en dehors de ca, si je me met sur un point de vue plus objectif tous ces outils sont effectivement l'avenir, je le pense vraiment :)
NextGine : 3D games engine
Nombre de lignes actuel : 77683 |
|
| Mod |
Posté le 26 Fév 2009 à 16:20
|
|
![]() Messages : 4954 GCPoints : 2100823 |
Un petit complément d'informations : J'ai commencé à effectuer quelques mesures de temps sur le Garbage Collector de JadeBasic, ou plutôt l'embryon de Garbage Collector de JadeBasic, et les résultats sont pour le moins surprenants. Je n'ai pas de réel point de comparaison avec d'autres langages, je vais donc m'atteler à présenter ces chiffres sous l'angle le plus brut : du temps. Le code ayant servi au tests est relativement simple : Code : a = GetTime() x as Test while (i < 10000) i = i + 1 x = new Test endwhile y as Test() y = new Test() b = GetTime() collect c = GetTime() PrintInt(b - a) PrintInt(c - b) Pause() class Test a as integer b as integer c as integer d as integer endclass Comme vous pouvez le constater, il s'agit tout simplement de créer 10000 objets de la classe "Test", tout en mesurant le temps de création, puis de lancer une collecte de ces mêmes objets, là encore en mesurant le temps nécessaire pour effectuer la collecte. L'objet "y" créé en dernier sert à avoir une référence vers un objet devant être déplacé, ce qui augmente le temps de collecte. Pour information, la fonction "GetTime", qui provient de la toute nouvelle librairie dédiée à la gestion du temps, retourne une valeur en millisecondes, fonction basée sur le "GetTickCount" de Windows. Pour l'allocation, tout d'abord, le résultat est assez simple à interpréter : 0 millisecondes. C'est tout simplement instantané. Et pour la collecte, nombre non moins intéressant : 422 millisecondes. Il s'agit maintenant de le relativiser, ce nombre. Dans quels cas un jeu serait-il amené à détruire 10000 objets en temps réel, ou même tout simplement d'en avoir 10000 simultanément (les tableaux étant gérés différemment) ? A première vue, ça me semble tout de même assez bon pour un code basé sur la fonctionnalité plus que la rapidité. J'ai tout de même été un peu plus loin dans les quantités d'objets à créer, à savoir 50000, et j'obtiens ceci : Allocation : 0 millisecondes Collecte : 18,010 secondes Dans le premier cas, difficile de faire mieux (après test avec un malloc au lieu d'un appel au GC, le tout dans un environnement avec de la mémoire libre, j'obtiens également ce résultat). Le second cas, avec ses 18 secondes, fait quant à lui assez peur. On pourra déjà commencer par remarquer que le résultat n'est pas multiplié par cinq, et c'est parfaitement logique, sachant que pour chaque objet créé on effectue un test par rapport à la totalité des objets existants. La courbe de croissance du temps de collecte est donc exponentielle. Egalement, on retombe dans le même cas qu'auparavant : quel programme pour utiliser autant d'objets à détruire en temps réel ? Cette remarque mis à part, il est bien évident qu'un tel temps de suppression est totalement inacceptable, et je travaillerai donc là dessus en priorité lors des prochaines modification du Garbage Collector. Mais pour conclure, dans l'ensemble, ces résultats sont plutôt encourageants pour un code non optimisé. Un bon point nettement en faveur de la conservation du Garbage Collector. |
|
| SEB |
Posté le 26 Fév 2009 à 16:52
|
|
![]() Messages : 554 GCPoints : 103313 |
Je vais encore faire mon chieur :p je peu? je sais pas pourquoi je suis motivé aujourd'hui. Je trouve les résultats assez bons :) Cependant ca me surprend les allocations à 0 milisecondes... meme avec un malloc? 10000 allocations en 0 milisecondes ??? ou alors j'ai pas bien compris :D
NextGine : 3D games engine
Nombre de lignes actuel : 77683 |
|
| Mod |
Posté le 26 Fév 2009 à 19:16
|
|
![]() Messages : 4954 GCPoints : 2100823 |
Je n'ai pas précisé que la fonction de temps était basée sur GetTickCount pour rien ;). Cela induit une certaine imprécision sur les mesures, même si faible. Et pas si chieur que ça, quand j'ai obtenu ces résultats qui à première vue avait l'air très peu honnêtes, j'ai soupçonné un bug. Pour l'allocation via Garbage Collector, normal, même si étonnant, vu que l'on n'alloue pas directement de la mémoire système, mais de la mémoire virtuelle. Pour l'allocation via malloc, je viens de prendre le temps de tester de façon plus radicale, en allouant des paquets de 1,6Ko de mémoire, et l'application prend en place en mémoire quelque chose comme 18 Mo (compter la mémoire allouée par le Garbage Collector là dedans, soit environ 2,2 Mo), et 16 millisecondes. Donc aucun doute à avoir là-dessus, les 10000 allocations sont bien instantanées. Je mets ce résultat sur le compte des très petites allocations (20 octets), et du fait que le code assembleur généré est minimaliste. Et après test en C++ (Visual Studio), à code équivalent, j'obtiens une valeur de 125 millisecondes. |
|
Page précédente


