Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Project CAMP - open-source reflection library for C++  (Read 24790 times)

0 Members and 1 Guest are viewing this topic.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Project CAMP - open-source reflection library for C++
« on: June 15, 2010, 12:55:39 pm »
Hi

This time I'm not going to talk about SFML, but rather about another project that I'm working on: CAMP.

CAMP is an open-source library (under the LGPL license) that allows to emulate reflection features in C++, like you can find in Java, .Net, etc. In short, reflection allows to manipulate classes, functions, properties and objects dynamically without having to know about (at compile time) their existence, their name or even their prototype.

So what can you do with CAMP? Well, for those who know Qt and its QObjects with abstract signals, slots and properties, you can basically do the same thing with CAMP. But it's not limited to that, we can also imagine a variety of applications based on meta-information: automatic serialization in XML or other format, a generic object editor, writing bindings to script languages in a few lines of code, ...

For example, I think about all the GUI libraries based on CAMP that are being written: they could potentially use CAMP to handle their signals, slots and properties and use them to write XML import/export of widgets, or a designer with a widget editor, etc.

We recently published a brand new website for the community, with a forum, a wiki, a bug tracker, a file repository, etc. :
http://dev.tegesoft.com/projects/camp

Don't hesitate to give me your feedback, and to ask questions if you don't understand everything of CAMP :)
Laurent Gomila - SFML developer

Ashenwraith

  • Sr. Member
  • ****
  • Posts: 270
    • View Profile
Project CAMP - open-source reflection library for C++
« Reply #1 on: June 15, 2010, 02:02:40 pm »
Hi, CAMP sounds great. I remember doing serialization in Java many, many years ago.

I believe I used it for networking/file transfer.

I'm curious though, what are the advantages over using a script binding like AngelScript (I was thinking of using that for my GUI setup)?

I assume it would also be good for saving complex game states (which could be reused for netowrking or playback)?


Any other ideas you might have for games/SFML apps?

Maybe a history/undo system?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Project CAMP - open-source reflection library for C++
« Reply #2 on: June 15, 2010, 02:13:03 pm »
Quote
I'm curious though, what are the advantages over using a script binding like AngelScript (I was thinking of using that for my GUI setup)?

I guess that the AngelScript binding allows you to use your classes only in AngelScript :)
CAMP is an abstract binding library, once your classes are declared you can use the binding for anything, not just for the X script language.

Quote
I assume it would also be good for saving complex game states (which could be reused for netowrking or playback)?

Absolutely.

Quote
Any other ideas you might have for games/SFML apps?

In the game studio where I worked before, we used intensively a similar library of our own in 3 main areas:
- binding the game entities to script (we used GameMonkey)
- automatic import/export to XML
- editing game objects in the level editor
It was really powerful because all that we, the developers, had to write, is the abstract interface of the new classes. Then the game designers would automatically see the new class in their scripts, in the level editor and in the configuration files. And all these three things use the same, unified interface (class, functions and properties names).
It was really a huge time saver!
Laurent Gomila - SFML developer

gsaurus

  • Sr. Member
  • ****
  • Posts: 262
    • View Profile
    • Evolution Engine
Project CAMP - open-source reflection library for C++
« Reply #3 on: June 15, 2010, 08:42:08 pm »
Quote from: "Laurent"

In the game studio where I worked before, we used intensively a similar library of our own in 3 main areas:
- binding the game entities to script (we used GameMonkey)
- automatic import/export to XML
- editing game objects in the level editor
It was really powerful because all that we, the developers, had to write, is the abstract interface of the new classes. Then the game designers would automatically see the new class in their scripts, in the level editor and in the configuration files. And all these three things use the same, unified interface (class, functions and properties names).
It was really a huge time saver!


It looks great from what you say. May be of good help for me since I plan to use Lua, make editors, save/load states etc. However this is quite new for me and I'm not getting how it would effectively help. I know this abstraction level from other languages but I never made big use of it and I never imagined it with C++.

I looked at the CAMP page and its tutorials, but I still don't know how it can ease things, I might need a concrete example of application, an example with CAMP to bind a class to Lua or in a simplistic GUI editor, or to store objects in binary files for example. That may be something to be added on the CAMP wiki tutorials.

What would make someone opt by CAMP instead of luabind to bind classes to Lua? Or to use CAMP to modify objects in a level editor instead of doing the same using the classes themselves? (I'm imagining a class Level witch is a matrix where you add and remove entities, each entity with an integer field energy for instance)
How does the CAMP abstraction surpass the abstraction gained from interfaces (abstract C++ classes), witch already hide modules implementations and enables to modify/change the implementations keeping the same interfaces for scripts/gui editor/storage?
Pluma - Plug-in Management Framework

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Project CAMP - open-source reflection library for C++
« Reply #4 on: June 15, 2010, 08:55:13 pm »
Quote
I looked at the CAMP page and its tutorials, but I still don't know how it can ease things, I might need a concrete example of application, an example with CAMP to bind a class to Lua or in a simplistic GUI editor, or to store objects in binary files for example. That may be something to be added on the CAMP wiki tutorials.

We're currently working on adding more examples to the wiki :)

But for what you're talking about, which are real-life examples, we'll even write the corresponding generic modules, so that users can directly use them without writing a single line of Python / Lua / XML / GUI / whatever code.

Quote
What would make someone opt by CAMP instead of luabind?

Using Luabind would be very similar to using CAMP, but then what? You have a nice binding of all your C++ types so that you can use them in Lua, but nowhere else. If you want to write a Python binding you will have to duplicate the exact same code with boost.python, and do this step over and over for each module that you write.
Declaring a meta-class with its functions and properties is a generic step, it shouldn't be tied to a script language or whetever. That's what CAMP allows. "Bind once, use everywhere".

Quote
Or to use CAMP to modify objects in a level editor instead of doing the same using the classes themselves?

This is the other side of the problem. You write some code that allows you to edit objects of class X in an editor, fine. But  then you want to edit objects of class Y in the same kind of editor, so what do you do? You have to write the same code, again and again for every class that you want to be able to edit.
Using CAMP, you write the code once using the CAMP abstraction, and badaboum it works for all your classes.

In other words:
Without CAMP
- You say "this class is named X in Lua, it contains ... properties and ... functions in Lua"
- Then you use these declarations in Lua
- You say "this class is named X in Python, it contains ... properties and ... functions in Python"
- Then you use these declarations in Python
- You say "this class is named X in XML, it contains ... properties and ... functions in XML"
- Then you use these declarations in XML

With CAMP
- You say "this class is named X, it contains ... properties and ... functions"
- Then you use these common declarations in Lua, Python, XML, etc.
Laurent Gomila - SFML developer

pdusen

  • Newbie
  • *
  • Posts: 30
    • View Profile
Project CAMP - open-source reflection library for C++
« Reply #5 on: June 15, 2010, 09:02:26 pm »
Quote from: "Laurent"
We're currently working on adding more examples to the wiki :)

But for what you're talking about, which are real-life examples, we'll even write the corresponding generic modules, so that users can directly use them without writing a single line of Python / Lua / XML / GUI / whatever code.


I think that the entire concept will be much clearer once this as done. The existing wiki content does a fairly good job explaining how to bind to CAMP, but doesn't really explain how that relates to any other language bindings.

I'm looking forward to further developments with CAMP. Generic handling of language bindings within the compiler itself is a very appealing idea to me.

gsaurus

  • Sr. Member
  • ****
  • Posts: 262
    • View Profile
    • Evolution Engine
Project CAMP - open-source reflection library for C++
« Reply #6 on: June 15, 2010, 09:02:33 pm »
Quote from: "Laurent"
we'll even write the corresponding generic modules, so that users can directly use them without writing a single line of Python / Lua / XML / GUI / whatever code.

Great! :)

Quote
"Bind once, use everywhere".
Ok got it about the scripting  :wink:

Quote
You write some code that allows you to edit objects of class X in an editor, fine. But  then you want to edit objects of class Y in the same kind of editor, so what do you do? You have to write the same code, again and again for every class that you want ot be able to edit.
Using CAMP, you write the code once using the CAMP abstraction, and badaboum it worls for all your classes.

What about interfaces? X and Y extends the same abstract C++ interface and so the code remains the same for all classes of same type, what's the advantage of CAMP over that?
(Sorry I may have edited my post while you was answering)
Pluma - Plug-in Management Framework

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Project CAMP - open-source reflection library for C++
« Reply #7 on: June 15, 2010, 09:14:06 pm »
Quote
What about interfaces? X and Y extends the same abstract C++ interface and so the code remains the same for all classes of same type, what's the advantage of CAMP over that?

But you still have a lot of different interfaces, so a lot of duplicated code. With CAMP, the code remains the same for all your classes (even the ones that you've not written yet).

And interfaces don't allow derived classes to have their own specific members. CAMP does.
Laurent Gomila - SFML developer

gsaurus

  • Sr. Member
  • ****
  • Posts: 262
    • View Profile
    • Evolution Engine
Project CAMP - open-source reflection library for C++
« Reply #8 on: June 15, 2010, 09:35:56 pm »
Hm, I don't know if that convinces me.

Quote from: "Laurent"
And interfaces don't allow derived classes to have their own specific members. CAMP does.
I didn't get it. With CAMP you assume that some functions and properties exists on whatever object you're manipulating. Those objects may have a lot of other things, but they respect the meta-class functions and properties. They can have different names or even be declared in different classes, but the structure of functions and properties is well defined. If you modify the meta class, you have to modify the code that use those objects, right? Same as with interfaces, classes can have a lot of other things inside but from outside you only use what you're expecting (witch is defined on the interface).

I'm not seeing much difference between a meta class and an interface. An interface defines the structure of derived classes, so it's somehow a meta class too. The lack of own members "binded" as public members may be bypassed with getters/setters, no?
Pluma - Plug-in Management Framework

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Project CAMP - open-source reflection library for C++
« Reply #9 on: June 15, 2010, 10:43:36 pm »
Ah, I see why you're not convinced, there's something that you haven't figured out yet :)

Quote
With CAMP you assume that some functions and properties exists on whatever object you're manipulating
...
they respect the meta-class functions and properties
...
the structure of functions and properties is well defined
...
If you modify the meta class, you have to modify the code that use those objects, right?

This is what you get with a C++ base class, yes. But with CAMP this is no longer true. You're not relying on a fixed, known interface: you ask CAMP what classes exist, and what functions and properties they declare. The code contains nothing hard-coded such as a name or a prototype, everything is abstracted and manipulated dynamically.

This is what reflection is: you ask the class what members it has, you no longer have to know it statically.
Laurent Gomila - SFML developer

gsaurus

  • Sr. Member
  • ****
  • Posts: 262
    • View Profile
    • Evolution Engine
Project CAMP - open-source reflection library for C++
« Reply #10 on: June 15, 2010, 11:59:10 pm »
Hm, well I know.. I think my problem is that I'm not used to deal with dynamic structure :wink:, I'm not seeing where/what dynamic variety can I add to my code that I can't do statically with abstract classes.

Instead of doing "object.call("func");" we can do "object.call(somethingRealisedInRuntime)", and this is the main difference to static interfaces. But I can't imagine how the code that handles those calls can deal with such variety. Whatever the calls are and whatever they do behind, the caller is usually expecting some kind of return value (to handle after the call for example). The caller code is at least partially static, perhaps it can route the results of a dynamic call into another dynamic object, but there's still some "static" communication mechanism inherent.

I see that it gives more flexibility, maybe I'm just not realising how and in what I could use it for my editor tools, what kind of functions would work with that witch can't be or is substantially harder to do with abstract classes. I can't imagine two objects with different interfaces being threatened by the same code, if they are threatened the same way, that's already a defined abstract way of threatening them (then a common interface).


But as for the bindings for XYZ I think it's great. Reminds me of this, but better as it's a very dynamic approach.
Pluma - Plug-in Management Framework

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Project CAMP - open-source reflection library for C++
« Reply #11 on: June 16, 2010, 12:14:42 am »
Maybe I should give you an example

Code: [Select]

QWidget* createObjectEditor(const camp::UserObject& object)
{
    ObjectEditor* objectEditor = new ObjectEditor;

    const camp::Class& metaclass = object.getClass();
    for (std::size_t i = 0; i < metaclass.propertyCount(); ++i)
    {
        const camp::Property& property = metaclass.property(i);

        QWidget* memberEditor;
        switch (property.type())
        {
            case camp::boolType :
                memberEditor = new BoolEditor(property, object);
                break;

            case camp::intType :
                memberEditor = new IntEditor(property, object);
                break;

            case camp::realType :
                memberEditor = new RealEditor(property, object);
                break;

            case camp::stringType :
                memberEditor = new StringEditor(property, object);
                break;
        }

        objectEditor->addItem(property.name(), memberEditor);
    }

    return objectEditor;
}

int main()
{
    A x1;
    std::string x2;
    MyFunkyClass x3;

    QWidget* editor1 = createObjectEditor(x1);
    QWidget* editor2 = createObjectEditor(x2);
    QWidget* editor3 = createObjectEditor(x3);

    return 0;
}

Don't look in depth into this code, it's crappy and written from scratch :)

But what's important here is that I've written a generic object editor that can work on any class, as long as the class is declared to CAMP. Thanks to CAMP I can dynamically retrieve all the class' properties, and create editor widgets according to their type and name. How can you do that with a C++ base class (one that doesn't provide the features of CAMP from scratch, of course ;))?

Quote
But as for the bindings for XYZ I think it's great. Reminds me of this, but better as it's a very dynamic approach.

It's not really the same purpose. SWIG will parse your source files to generate the source code of a module for the script language of your choice. The module is then compiled and loaded directly into the script language, it doesn't interact with your C++ program.

Quote
But as for the bindings for XYZ I think it's great.

Then it's great for anything else: accessing your C++ data structures through a script is the same as accessing them through an XML description or from an interactive GUI editor. These are just different ways of manipulating the same layer of abstraction.
Laurent Gomila - SFML developer

gsaurus

  • Sr. Member
  • ****
  • Posts: 262
    • View Profile
    • Evolution Engine
Project CAMP - open-source reflection library for C++
« Reply #12 on: June 16, 2010, 01:35:11 am »
I see.
Quote
How can you do that with a C++ base class (one that doesn't provide the features of CAMP from scratch, of course ;))?

A base class ValueType with methods getType() and getValue(). From this we derive the classes Bool, Int, Real, String (whatever else). Each object that is passed to the editor function may derive from a class with an array of ValueType objects. And the switch does basically the same.
A little bit simplified by no extra code&encapsulations about metaclass based programming (bindings etc). On the class implementations it's not great having such classes for those primitive types (not very annoying anyway, reminds me of java Integer, Boolean etc).

I don't feel secure enough with meta-class programming, the dynamic behaviours are harder to track, I'm not sure.. I don't feel enough control over such abstract variations, a function, a property can be anything. Maybe I'll get used one day and find it really useful and simpler (for codding and code reading) over abstract classes.  :roll:



The bindings for scripting/XML/Binary etc, are simpler because we don't have to bind tons of user defined types anymore, they are "translated" to your unified types, which can easily be translated to whatever else. Code the translation CAMP -> XYZ once and everything bound to CAMP will be bound to XYZ, that's how I see it (am I wrong?). As extra advantage, it is used the same way on languages that has this kind of features rooted, making the inter-programming easier.
But if to use within C++ applications only I don't see (yet) many advantages other than the serialization.
Pluma - Plug-in Management Framework

Ceylo

  • Hero Member
  • *****
  • Posts: 2325
    • View Profile
    • http://sfemovie.yalir.org/
    • Email
Project CAMP - open-source reflection library for C++
« Reply #13 on: June 16, 2010, 02:23:50 am »
Kinda obstinate eh..

Well I can see one other simple example : with an UI designer, to connect callback functions.

Imagine an UI designer where you save the function name to be called when an action occurs.

With CAMP you would tell which controller object is to be used when loading the UI, and then the GUI would just have to find the method with that name and call it through CAMP.

Without CAMP, how can you define a dynamic link between a function name and your code ? Unless the UI designer produces source code containing a static class of course (as QTCreator does).
Want to play movies in your SFML application? Check out sfeMovie!

Ashenwraith

  • Sr. Member
  • ****
  • Posts: 270
    • View Profile
Project CAMP - open-source reflection library for C++
« Reply #14 on: June 16, 2010, 02:49:42 am »
Quote from: "Ceylo"
Kinda obstinate eh..

Well I can see one other simple example : with an UI designer, to connect callback functions.

Imagine an UI designer where you save the function name to be called when an action occurs.

With CAMP you would tell which controller object is to be used when loading the UI, and then the GUI would just have to find the method with that name and call it through CAMP.

Without CAMP, how can you define a dynamic link between a function name and your code ? Unless the UI designer produces source code containing a static class of course (as QTCreator does).


Ah, if I'm not mistaken I do this a lot in javscript when creating DHTML interfaces and it's very useful (especially since you want the least code possible for compression). Wow, this sounds like CAMP allows a lot the javascript tricks for dynamically generating/using code so you write less overall.

I need to do some experiments later.

The only thing I"m really concerned about is speed/resource overhead.