:bravo:
Version imprimable
:bravo:
Hello,
Je commence à utiliser CAMP régulièrement pour la génération automatique d'éléments graphiques et je dis un grand bravo, la lib est bien complète et vraiment facile à utiliser :ccool:.
J'utilise également boost.python et je me demandais quelle forme prendrait le module d'interfaçage avec python? S'agit-il d'encapsuler des appels à boost.python depuis CAMP? Ou comptes tu refaire l'encapsulation de l'API CPython (en gros quel niveau de compatibilité entre les deux libs)?
Merci :)Citation:
Je commence à utiliser CAMP régulièrement pour la génération automatique d'éléments graphiques et je dis un grand bravo, la lib est bien complète et vraiment facile à utiliser
boost.python, en gros c'est CAMP + son module Python réunis en un seul bloc. Il n'y a donc aucun intérêt à utiliser boost.python pour le module Python de CAMP, puisque toute la partie binding de classe et introspection existe déjà. On n'a réellement besoin que de l'API C de Python.Citation:
J'utilise également boost.python et je me demandais quelle forme prendrait le module d'interfaçage avec python? S'agit-il d'encapsuler des appels à boost.python depuis CAMP? Ou comptes tu refaire l'encapsulation de l'API CPython (en gros quel niveau de compatibilité entre les deux libs)?
Ok, donc a priori on pourra exposer nos classes avec une lib ou l'autre (dans CAMP une unique exposition pour python et les metaclass) et continuer à utiliser la partie manipulation d'objets python avec boost.python (ou autre). Ca à l'air nickel :DCitation:
boost.python, en gros c'est CAMP + son module Python réunis en un seul bloc. Il n'y a donc aucun intérêt à utiliser boost.python pour le module Python de CAMP, puisque toute la partie binding de classe et introspection existe déjà. On n'a réellement besoin que de l'API C de Python.
Ca a pris un peu plus de temps que prévu, mais nous avons enfin un site fonctionnel et complet pour le projet :
http://dev.tegesoft.com/projects/camp
Le site (basé sur redmine) est assez complet : il y a un wiki avec des tutoriels, une roadmap, un système de tickets pour rapporter des bugs/fonctionnalités, un dépôt contenant les fichiers de toutes les versions.
Nous en avons également profité pour publier officiellement la version 0.7.0 sous licence LGPL. Nous travaillons d'ores et déjà activement sur la prochaine release.
N'hésitez pas à venir vous enregistrer pour donner votre avis :)
Maintenant que tout est prêt pour la communauté, j'espère vraiment que cette bibliothèque pourra servir à pas mal de monde et évoluer.
Merci pour ton travail :ccool: j'espère aussi que la librairie rencontrera un certain succès auprès de la communauté
Faut définitivement que je me penche dessus. (et sous le capot surtout).
Ca a l'air vraiment sympa et propre point de vue client, super travail déjà rien que de ce point de vue !
Je ne compte pas l'utiliser dans l'immédiat, mais je sais que j'en aurais très certainement l'utilité très très bientôt :).
Perso dans notre projet, CAMP c'est que du bonheur ! Ca marche au poil ! :ccool:
Bonjour,
CAMP me semble tres interessant.
Je pense qu'il permettrait notemment d'implementer un framework d'injection
de dependences.
Je verrais bien quelque chose dans ce gout la, en s'inspirant de Google Guice :
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141 using namespace camp; class Module { public: virtual ~Module (); protected: virtual void configure () = 0; virtual Module& bind (Class& c); virtual Module& to (Class& c); template <typename Scope> Module& as (); }; class Injector { public: virtual ~Injector (); static Injector& create (const std::list<Module*>& modules); template <typename T> void destroy (T& c); template <typename T> T& instance (Class& c); protected: Injector (); }; class A { public: A () { Class::declare<A>("A") .constructor(); } virtual ~A () {} }; class B : public A { public: B () { Class::declare<B>("B") .constructor(); } virtual ~B () {} }; class D { public: D () { Class::declare<D>("D") .constructor(); } virtual ~D () {} }; class E { public: E (A& a, D& d) : a (a), d (d) { Class::declare<E>("E") .constructor<A, D>(); } virtual ~E (); A& a; D& d; }; class MyModule1 : public Module { public: virtual ~MyModule1 () {} protected: virtual void configure () { // Simple binding bind(Class::classByType<A>()).to(Class::classByType<B>()); // Singleton binding bind(Class::classByType<D>()).as<Singleton>(); } }; class MyModule2 : public Module { public: virtual ~MyModule2 () {} protected: virtual void configure () { // Direct implementation binding bind(Class::classByType<D>()); bind(Class::classByType<E>()); } }; int main (int argc, char** argv) { using boost::assign::list_of; Injector& injector = Injector.create(list_of (new MyModule()) (new MyModule2())); // From MyModule1 A& a1 = injector.instance(Class::classByType<A>()); A& a2 = injector.instance(Class::classByType<A>()); assert (&a1 != &a2); // From MyModule2 D& d1 = injector.instance(Class::classByType<D>()); D& d2 = injector.instance(Class::classByType<D>()); assert (&d1 == &d2); E& e = injector.instance(Class::classByType<E>()); assert (&e.a != &a1 && &e.a != &a2); assert (&e.d == &d1 && &e.d == &d2); injector.destroy(e); // delete on &e.a and &e // delete everything which is not destroyed yet delete &injector; return 0; }
Je pense qu'il y a pas mal de développeurs C++ qui ne sont pas encore familiers avec le concept d'injection de dépendances, à commencer par moi. J'ai un peu de mal à saisir ce que tu proposes, même avec l'exemple. Est-ce que tu pourrais expliquer ce que sont censées faire les fonctions dont tu n'as pas donné le code (bind, to, as, ...), et ce qu'accomplit concrètement leurs appels ?Citation:
Je pense qu'il permettrait notemment d'implementer un framework d'injection
de dependences.
J'avais en tete ce que propose le framework de Google, Guice.
L'idee est de piloter toute l'instanciation des classes de ton projet et
leur cycle de vie par un framework.
Ca peut sembler un peu delirant au premier abord, mais a terme ca apporte
un grand confort dans le developpement.
Rapidement, l'idee est de pouvoir mapper des classes abstraites (ou interfaces en Java) a une implementation ou alors directement une implementation.
Ensuite lorsque tu ecris une classe qui va dependre (parametres dans le constructeur) de classes abstraites, le framework va etre capable bien evidement d'instancier ta classe mais aussi ses dependences (implementations des interfaces) en construisant un graphe de dependences et en faisant un tri topologique afin de recuperer l'ordre d'instanciation des classes.
Cela permet entre autre de s'affranchir de l'ecriture de Factories.
Ensuite, connaissant le graphe de dependences de tes classes, tu vas pouvoir aussi gerer leur cycle de vie et ainsi leur destruction.
Guice ajoute la notion de Scope permettant de definir la duree de vie des instances (exemple avec le Singleton) et la possibilite de definir ses propres Scopes.
Guice permet donc l'injection de dependences mais aussi des fonctionnalites plus avancees comme l'injection d'intercepteurs permettant de faire de la programmation orientee aspect.
Je t'invite a aller jetter un oeil au lien vers Guice au debut de mon message.
Alors evidemment le Java apporte un grand confort via les annotations pour ce genre de chose, mais je pense que moyennant les quelques lignes de description via CAMP, on peut tendre vers certaines des fonctionnalites interessantes de Guice.
Les methodes bind(), to(), as() viennent de Guice, tu pourras voir un exemple dans le Getting Started.
bind/to permet de faire un mapping entre une classe abstraite et son implementation afin que le framework soit informe de l'implementation a injecter lorsqu'il doit resoudre une dependence abstraite.
Un autre interet de l'injection de dependence est la facilite de faire evoluer du code.
Si tu rajoutes une dependence a ta classe (nouveau parametre dans le constructeur) et que celle-ci est geree par le framework d'injection de dependences (en ayant realise le binding), tu n'auras pas besoin de modifier tout le code d'instantiation (potentiellement en cascade si les dependences sont transmises de classes en classes) puisque c'est le framework lui meme qui prend en charge les instantiations.
Hum... Etant donné qu'en C++ il n'a y pas de garbage collector comme en java, ça veut dire que ton framework gère l'intégralité des objets créés, y compris la construction et destruction. Je suis pas sûr que ce soit hyper compatible avec la destruction déterministe des objets en C++, notamment avec l'approche RAII.
Celà dit, j'ai lu rapidement, il est tard là ! Je vais regarder un peu plus en détail dès que j'aurai plus de temps ! ;)
Oui il faudrait faire un appel explicite a une methode pour la destruction d'une instance mais connaissant les dependences de cette instance, tu peux aussi les detruire si ton instance est la seule a dependre d'elles et qu'elles ne sont pas declarees comme etant des singletons.
L'idée d'utilisation de CAMP de zeppelinux me plaît beaucoup !
Et doter le framework d'un garbage collector maison est tout à fait faisable, éventullement via un mécanisme intrusif d'AddRef/Release.
Ou comment faire du java en C++.. autant lancé netbeans / eclipse et faire du java ..
Goten, l'idee n'est evidement pas de faire de l'injection de dependence dans un contexte ou l'on a de fortes contraintes en matiere de determinisme temporel (par exemple).
Mais c'est tout a fait envisageable pour du code classique sachant que l'overhead dans l'utilisation d'un tel framework n'est pas enorme en matiere de temps du fait que le plus gros du boulot (construction du graphe) se passe a l'initialisation.
Apres l'idee de CAMP c'est aussi de combler les lacunes du C++ en matiere d'introspection, concept present dans beaucoup de langages et notemment le Java qui s'appuie tres fortement sur celui-ci.
Donc s'inspirer de technologies venant de d'autres mondes comme Java ne me semble pas forcemment deconnant a partir du moment ou c'est realisable.
Je pense que Goten réagissait surtout au propos par rapport au garbage collector ? C'est le truc qui fait tilter souvent et qui fait dire "bah va faire du java à la place".
Là on parle d'un garbage collector calibré spécifiquement pour ce framework. D'ailleurs, il n'y a qu'à lire ce qu'en dit ce cher Bjarne. Il n'y a pas de raison de se priver d'un garbage collector en C++ sous prétexte que java en a déjà un. Le fait est qu'on a le choix et qu'on peut le gérer soi même finement, PAS comme java.
L'injection de dépendance... ça serait pas utile pour des framework web façon CPPCMS?
Le GC n'est pas la seule différence entre le Java et le C++. shared_ptr peut être assimilé à un garbage collector, quelque part. Pourtant c'est pas pour autant que le C++ se transforme d'un coup en java parce qu'on a plus de delete :calim2:.
Les templates, le contrôle complet de l'allocation, la surcharge d'opérateurs, l'héritage multiple, avoir des classes sans méthodes virtuelles, etc...
Je réagissais à un tout, pas qu'au gc. Et le Père peut vouloir un gc c'est pas pour autant que je suis d'accord. Je préfère une approche déterministe personnellement. (d'autant plus qu'un gc __celui de java en tout cas__ ça se met en défaut aisément).
Le jour où tu feras quelque chose de non-déterministe sur un PC tu m'appelles ^^.
Le but de tout programmeur, c'est de simplifier sa tâche compliquée à chaque étape du développement. CAMP permet une solution simple à certains problèmes très compliqués. shared_ptr permet de simplifier d'autres problèmes, l'injection de dépendances permet de simplifier encore des problèmes différents, etc etc. De plus, tout cela fait partie de la séparation de rôles, qui est un pillier très important de la programmation orienté objet. Le nier c'est de descendre le C++ au niveau de l'assembleur. Autant faire de l'assembleur dans ce cas !
De toutes manières, tant que cela reste du C++ pur et n'impose pas de devoir faire tourner son logiciel dans un environnement précis, alors pour moi tout est bon à prendre
Bref, je pense qu'il est inutile de polluer ce topic, si tu veux en discuter d'avantage, je te propose de créer un topic :).
Non mais ça me rassure, y a pas qu'à moi que CAMP fait pensais sévèrement à du JEE/spring >< !
M'enfin, si c'est pour faire ça, je préfère les @remote à toute ces lignes compliqué -_-' !
Mais quand même, chapeau bas !
Pour les inje de dépendance, je crois que y a un tuto spring sur la partie java du site.
Salut,
C'est quoi ton PC ? Parce que le mien, j'ai parfois des doutes entre ce qu'il fait et ce que je veux qu'il fasse. :mouarf:
En fait, je me demande si je ne pense pas le contraire (mais c'est un autre débat).
On voit avec cette discussion à quel point CAMP peut être intéressant vu la variété de chose qu'il permet de faire. On sent que c'est là sa puissance. Probablement qu'il y a encore d'autres pistes à explorer.
En tout cas, moi je dit chapeau bas à Laurent et son équipe :hola:
C'est chose faite.
Sur le wiki de CAMP, j'explique comment CAMP a résolu la modification d'objets depuis une interface graphique via l'introspection.
C'est ICI ! ;)
J'espère que ça éclairera du monde, car cette lib, elle vaut de l'or ! :ccool:
Nous venons d'écrire un module XML :
http://dev.tegesoft.com/projects/camp/wiki/Camp_xml
N'hésitez pas à l'essayer et à nous donner votre avis :ccool:
Je prends note pour l'utililser dés que je reviens sur mon projet perso. Justement je dois faire de la serialization xml du modele que j'ai quasimment fini de mettre en place coté c++. Je vais tester avec QtXML
J'imagine qu'il faudra quand même passer par Qt pour la vérification via xsd?
Oui. camp-xml est un module très simple de sérialisation, XSD c'est complètement hors contexte ici.Citation:
J'imagine qu'il faudra quand même passer par Qt pour la vérification via xsd?
Ceci-dit si tu veux t'amuser je pense que tu peux créer un module qui crée un fichier XSD à partir d'une meta-classe ;)
Peut être si je trouve le temps mais j'en doute ^^;
je suis bien tenté par un serializer en Json... :-)
par contre je n'ai pas vu, est-elle multi-plateforme?
Bien entendu, ça n'utilise que du code C++ classique.
Sympa ce nouveau module xml !
Par contre, une question:
Je ne comprends pas trop ce que ça veut dire :oops:.Citation:
The most important limitation is about object properties. When such a property is processed, camp-xml assumes that the underlying object already exists and simply fills it. It won't be able to create it dynamically.
Est-ce l'objet qui doit être instancié avant la déserialisation ou bien est-ce la propriété ?
Et les pointeurs dans tout ça ?
Est-il possible de spécifier la manière dont certaines propriétés sont sérialisées ? (à l'instar de boost.serialization)
Ne serait-il pas possible de définir une interface sur laquelle viendra se coller plusieurs types d'objets qu'instancierait Camp ?
Exemple:
Ce genre de chose pourrait vraiment être superbe :DCode:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 struct PersonInterface { virtual void doStuff() = 0; virtual void doOtherStuff() = 0; }; struct Women : PersonInterface { /* propriétés propres à la femme */ void doStuff() {} void doOtherStuff() {} }; struct Man : PersonInterface { /* propriétés propres à l'homme */ void doStuff() {} void doOtherStuff() {} }; void registerPersonInterface { camp::Interface::declare< PersonInterface >() .function(doStuff) .function(doOtherStuff); } void registerWomen() { camp::Class::declare< Women >("Women") .implements( PersonInterface ) .property("na", &Women::na); } void registerMan() { // ... } CAMP_AUTO_TYPE( PersonInterface, ®isterPersonInterface ); CAMP_AUTO_TYPE( Women, ®isterWomen ); CAMP_AUTO_TYPE( Man, ®isterMan ); int main() { //ici, on peut déserialiser des femmes ou des hommes, par exemple. //l'instanciation du coup est déléguée à Camp :« PersonInterface& p = camp::xml::deserialize( root ); }
Je ne connais pas du tout les limites du projet, je ne donne donc que des idées à peut-être (ou pas) développer. Mais j'imagine déjà la possibilité de pouvoir déserialiser des types à partir d'une interface abstraite directement sur un socket (par exemple): ça serait vraiment la panacée !
Mais je me demande si c'est pas un peu hors des objectifs de Camp au final...
Ca veut dire que si tu as une propriété qui est un pointeur sur un objet, CAMP ne va pas pouvoir l'instancier avant d'affecter ses propriétés. Il ne peut que faire l'hypothèse qu'il est déjà construit. Si ce n'est pas le cas, boum.Citation:
Je ne comprends pas trop ce que ça veut dire
C'est faisable très facilement. Ca dévie un peu de ce que fait le module XML, mais il est tout à fait possible de proposer une variante qui sauvegarderait le nom de la classe pour pouvoir instancier et désérialiser l'objet convenablement. Dans ce cas, CAMP fait office de factory sans rien avoir à ajouter.Citation:
Ne serait-il pas possible de définir une interface sur laquelle viendra se coller plusieurs types d'objets qu'instancierait Camp ?
Même si je ne suis pas un fervant accro aux pointeurs, je pense que c'est tout de même une sacré limitation.
Ne serait-il pas possible de déclarer qu'une propriété est un pointeur et de lier la propriété à une fonction pour que Camp appelle celui-ci pré-déserialisation ? Avec quelques automatismes du style utiliser l'allocateur standard, afin de ne pas avoir à écrire une fonction d'instanciation spécifique à chaque fois ? En somme, prévenir Camp que la propriété est un objet alloué dynamiquement ? (pour ce qui est des objets partagés, je comprend très bien que c'est au programmeur de le gérer, et le noxml conviendrait parfaitement)
C'est une excellente nouvelle ! J'espère que ça cette fonctionnalité verra un jour le jour, rien que pour moi, ça m'ouvrirai énormément de portes quand à l'utilisation de la lib :D.Citation:
C'est faisable très facilement. Ca dévie un peu de ce que fait le module XML, mais il est tout à fait possible de proposer une variante qui sauvegarderait le nom de la classe pour pouvoir instancier et désérialiser l'objet convenablement. Dans ce cas, CAMP fait office de factory sans rien avoir à ajouter.
J'en doute. Il faut garder à l'esprit que CAMP offre des fonctionnalités très très génériques, et qu'allouer automatiquement un pointeur pour désérialiser l'objet correspondant est une chose très très spécifique. J'ai du mal à voir comment cette fonctionnalité s'inscrirait dans CAMP en dehors de ce contexte très spécifique.Citation:
Ne serait-il pas possible de déclarer qu'une propriété est un pointeur et de lier la propriété à une fonction pour que Camp appelle celui-ci pré-déserialisation ? Avec quelques automatismes du style utiliser l'allocateur standard, afin de ne pas avoir à écrire une fonction d'instanciation spécifique à chaque fois ? En somme, prévenir Camp que la propriété est un objet alloué dynamiquement ?
En plus ce n'est pas une limitation, il est toujours possible de gérer ça avec du code un peu personnalisé par rapport au module camp-xml.
Ce n'est pas une fonctionnalité qui doit voir le jour, tu peux déjà le faire.Citation:
J'espère que ça cette fonctionnalité verra un jour le jour, rien que pour moi, ça m'ouvrirai énormément de portes quand à l'utilisation de la lib
Je pense tout simplement qu'elle n'est pas prête pour ça, mais j'y penserai dans quelques mois/années :P
Je connaissais mirror, qui a une approche assez différente de CAMP, mais pas intro. Je vais jeter un coup d'oeil à ça :)
J'avais aussi entendu parler d'un projet boost pour abstraire boost.python et en faire un moteur de binding script générique, mais apparemment le projet a été abandonné faute de temps. Me rappelle plus le nom.
EDIT : j'ai retrouvé, c'est boost.langbinding