
Hello. I've been trying hard to implement the best possible properties sytem in c++ (version 0x). For now, I'm quite satisfied with the result, but it can be improved a little. The properties are implemented in a header called (surprisingly!) Property.hpp Classes: template TROProperty and TRWProperty for trivial properties, which are those which you can use very straightforward without defining setters or getters and it stores the property value inside. templates RWProperty and ROProperty, for which you need to define a storage (if needed) and getters and setters. FEATURES: - You can define a getter as a function that returns *ANYTHING* and it will deduce parameters, constness and everything it needs. - You can define a setter as a function that returns void and takes one parameter. The deduction machinery will do the rest. So, for trivial properties there is little to explain: class Person { public: TROProperty<unsigned int> Age; Person(int age) : Age(age) {} }; int main(int argc, char * argv[]) { Person p(26); cout << p.Age << endl; } For elaborated properties, you have freedom in defining the get and set functions, as long as the get function gets just one parameter and the set function sets one parameter and returns void. The usage of elaborated properties is done through a macro: class Agenda { typedef Agenda ClassName; //Needed for elaborated properties. vector<Person> persons_; Person * getCurrentPerson() { return persons_[Position]; } public: TrivialProperty<int> Position; PROP_ROPROPERTY(CurrentPerson); .... Agenda() : PROP_PROPERTY_INIT(CurrentPerson) {}; }; And now it's ready to be used. For now the features are: -Implicit conversion to the underlying type. -Operator overloading (just a sample of the possible operators, just implemented operator++ and some others) -Comparison operators... -Construction assignment, etc from any other property that has a convertible type or from a data type that makes sense. - Move and copy construction where it makes sense. - Compare, for example, a Property<int> to an int or another property with a convertible value to a Property<int>. If it makes sense, it must work. The same for any other operator. - You can obtain the underlying type for a property through operator(), which makes sense in some contexts. For example, suppose you have a class Person with properties Name, SurName and Age and a class Agenda with a property CurrentPerson which returns a pointer to a Person. You can do like this: string name = agenda.CurrentPerson().Name; you can assign Name to a string or any other property that accepts a string (untested but you could). But you don't need operator() when implicit conversion takes place. personsbyage_[aperson.Age] //No need for operator(), implicit conversion Caveats: ROProperty TROProperty I cannot enforce a private operator= because for that I need a workaround I don't know of or extended friend declarations, which are part of c++0x. So for now, these properties are exactly the same as their writeable counterparts without read-only enforcement. In the implementation part, for elaborated properties I have a template like this: template <class Getter, class Setter> class RWProperty; The same goes for ROProperty. Just with that and the macro to ease the writing of properties, you can get a property. These properties must be constructed with the this pointer AND the pointer to member functions. I'm experimenting (but I can't find a way to do it) with something like this: template <class Getter, class Setter, Getter, Setter> class RWProperty; so that the construction of properties wouldn't need the pointers, because they would be passed as template parameters. But inside the template I have an ambiguity problem. Getter and Setter are pointer to member function types and Getter and Setter parameters are the addresses. For now I've found the properties very usable. The only caveats are the enforcement of operator= and the passing of pointer to members as part of initialization. If I can solve those, we can get a good properties implementation of properties and the initialization of elaborated properties would be just with the this pointer (and a value if you want to initialize with a value). This is a work in progress. For now I've used c++0x, but I think I can use BOOST_TYPEOF (maybe) and some other things in order to translate it to current c++. The code is attached. It's an (unfinished) miniapplication of an Agenda made in gtkmm compiled under g++ 4.5 svn. Take a look at the Property.hpp and the application and tell me what you think. I would like to be able to pass pointer to member functions as template arguments in order to avoid initialization of pointers as parameters. compile with: g++ -std=c++0x `pkg-config gtkmm-2.4 --libs --cflags` Person.cpp Agenda.cpp Window.cpp main.cpp -o Agenda You can just add people with "Añadir" Button and traverse with < and > button. It does not do anything special, it's just to test properties.

On 1 Mar 2010, at 16:58, Germán Diago wrote:
Hello. I've been trying hard to implement the best possible properties sytem in c++ (version 0x).
For now, I'm quite satisfied with the result, but it can be improved a little.
The properties are implemented in a header called (surprisingly!) Property.hpp
Classes:
template TROProperty and TRWProperty for trivial properties, which are those which you can use very straightforward without defining setters or getters and it stores the property value inside.
templates RWProperty and ROProperty, for which you need to define a storage (if needed) and getters and setters.
FEATURES:
- You can define a getter as a function that returns *ANYTHING* and it will deduce parameters, constness and everything it needs. - You can define a setter as a function that returns void and takes one parameter. The deduction machinery will do the rest.
So, for trivial properties there is little to explain:
class Person { public: TROProperty<unsigned int> Age; Person(int age) : Age(age) {} };
int main(int argc, char * argv[]) { Person p(26); cout << p.Age << endl; }
How is this any different from:
class Person { public: unsigned int Age; Person(int age) : Age(age) {} };
int main(int argc, char * argv[]) { Person p(26); cout << p.Age << endl; }
? Chris

for trivial properties it's the same. But maybe in the future properties will be extended with some metadata. anyway, for trivial properties it's the same.

On 1 Mar 2010, at 18:24, Germán Diago wrote:
for trivial properties it's the same. But maybe in the future properties will be extended with some metadata. anyway, for trivial properties it's the same.
I don't understand what your library does. Having your most simple example say it does nothing at all is not helpful! Chris

On Mar 1, 2010, at 1:39 PM, Christopher Jefferson <chris@bubblescope.net> wrote:
On 1 Mar 2010, at 18:24, Germán Diago wrote:
for trivial properties it's the same. But maybe in the future properties will be extended with some metadata. anyway, for trivial properties it's the same.
I don't understand what your library does. Having your most simple example say it does nothing at all is not helpful!
Chris
Presumably it should allow you to create read amd write-only properties, for example, with arbitrary getter / setter functions. I would think so anyway, given the description. He alluded to this in the original post but there was no code sample demonstrating, only a code sample for trivial properties, which dont seem terribly useful. Zach

On Mar 1, 2010, at 2:48 PM, Zachary Turner wrote:
On Mar 1, 2010, at 1:39 PM, Christopher Jefferson <chris@bubblescope.net> wrote:
On 1 Mar 2010, at 18:24, Germán Diago wrote:
for trivial properties it's the same. But maybe in the future properties will be extended with some metadata. anyway, for trivial properties it's the same.
I don't understand what your library does. Having your most simple example say it does nothing at all is not helpful!
Where properties are useful is eliminating the need to define "setters/getters" while ensuring that no one ever gets a direct reference to the actual data. This is critical for multi-threaded programs where you want to reduce "shared state". My issue with the approach is that it drastically increases the size of your object and the cost of calling constructors. Presumably each "int" now has 2 member function pointers. Thus 4 bytes becomes 20 bytes (best case, 64 bit ptrs) and more on compilers that have bigger member function pointers. Best possible properties would have 0 per-instance overhead in either size or construction/destruction. Such a solution is possible and I hope to share it with the board soon. But put your mind to work and I am sure you can figure it out as I did in 30 minutes or less. It does require the use of macros however. Dan
Chris
Presumably it should allow you to create read amd write-only properties, for example, with arbitrary getter / setter functions. I would think so anyway, given the description.
He alluded to this in the original post but there was no code sample demonstrating, only a code sample for trivial properties, which dont seem terribly useful.
Zach _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On 1 Mar 2010, at 20:03, Daniel Larimer wrote:
On Mar 1, 2010, at 2:48 PM, Zachary Turner wrote:
On Mar 1, 2010, at 1:39 PM, Christopher Jefferson <chris@bubblescope.net> wrote:
On 1 Mar 2010, at 18:24, Germán Diago wrote:
for trivial properties it's the same. But maybe in the future properties will be extended with some metadata. anyway, for trivial properties it's the same.
I don't understand what your library does. Having your most simple example say it does nothing at all is not helpful!
Where properties are useful is eliminating the need to define "setters/getters" while ensuring that no one ever gets a direct reference to the actual data. This is critical for multi-threaded programs where you want to reduce "shared state".
My issue with the approach is that it drastically increases the size of your object and the cost of calling constructors.
Presumably each "int" now has 2 member function pointers. Thus 4 bytes becomes 20 bytes (best case, 64 bit ptrs) and more on compilers that have bigger member function pointers.
What exactly do you mean? struct X { int i; }; class X { int i; public: int geti() { return i; } void seti(int _i) { i = _i;} }; Are both the same size (sizeof(int)). Further, on any reasonable compiler geti, seti and in fact X itself will be totally optimised away, leaving just the same code as if we had used a raw int. Chris

On 3/1/2010 2:10 PM, Christopher Jefferson wrote:
Presumably each "int" now has 2 member function pointers. Thus 4 bytes becomes 20 bytes (best case, 64 bit ptrs) and more on compilers that have bigger member function pointers.
What exactly do you mean?
In order for a property ("Age" in the original example) to be able to reference other properties/members of its containing class, it needs a pointer to the object containing it. But now that I re-read Daniel's message, maybe he's suggesting that you'd have to have: struct foo { int data; int (*getter)(); void (*setter)(int); }; which is certainly unnecessary if you're being smart with templates. - Jim

On Mar 1, 2010, at 4:00 PM, James Porter wrote:
On 3/1/2010 2:10 PM, Christopher Jefferson wrote:
Presumably each "int" now has 2 member function pointers. Thus 4 bytes becomes 20 bytes (best case, 64 bit ptrs) and more on compilers that have bigger member function pointers.
What exactly do you mean?
In order for a property ("Age" in the original example) to be able to reference other properties/members of its containing class, it needs a pointer to the object containing it.
But now that I re-read Daniel's message, maybe he's suggesting that you'd have to have:
struct foo { int data; int (*getter)(); void (*setter)(int); };
which is certainly unnecessary if you're being smart with templates.
My assumption was that the class with the property would want the getter/setter to access other properties of the same class. For example, say you need to have a mutex around data and thus your setter/getter has something to do. So long as your setter/getter has no external context then why not just use a public data member? If the setter/getter of property A needs to maintain invariants on other properties then I fail to see how your property system would handle it.
- Jim
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

So long as your setter/getter has no external context then why not just use a public data member? If the setter/getter of property A needs to.
Because my plan is to add some metadata, probably, but this is another more long-term goal. See for the code sample. It has elaborated properties as well. I have been able to put the Getter and setter pointers as template arguments as of now (but not in the sample I attached in the mail). Every non-trivial property has two pointers (one to the getter and one to the setter) plus the object pointer. My goal is not to implement the most efficient properties in space, but to implement the most full-featured ones. It will be as close to C# properties as I can. The current implementation does not use std::function anymore, it uses plain pointer to member functions. All in all, what you have is a property system that can use getters and setters. To initialize elaborated properties you will need a pointer to this, and nothing else (the value if you want, but no function pointers in the arguments since they are passed through templates) The trivial properties store just the object itself, so they don't have (as of now) space overhead.
He alluded to this in the original post but there was no code sample demonstrating, only a code sample for trivial >properties, which dont seem terribly useful.
The code is attached in the mail.
Best possible properties would have 0 per-instance overhead in either size or construction/destruction. Such a solution is possible and I hope to share it with the board soon. But put your mind to work and I am sure you can >figure it out as I did in 30 minutes or less. It does require the use of macros however.
Please, explain me the way to do it. It will be very welcome. Thanks.

First quote :
In order for a property ("Age" in the original example) to be able to reference other properties/members of its containing class, it needs a pointer to the object containing it.
Second quote :
If the setter/getter of property A needs to maintain invariants on other properties then I fail to see how your property system would handle it.
Hello, You might want to give a glimpse at this previous thread : "[boost] [property] interest in C# like properties for C++?". 1/ you will see an interesting use of the defect 45 (<=> subclasses can access private members of parent class). More traditionnally, a friend might also have been used. 2/ no 'directly' stored pointer (recalculated at each access). 3/ lots of discussions on the subject. http://lists.boost.org/Archives/boost/2009/10/157143.php Best Regards, Pierre Morcello

Can I just make mention another implementation in case you are not already aware of it; Matthew Wilson's from his STLSoft libraries http://www.stlsoft.org/doc-1.9/group__group____library____properties.html Though the main documentation for it is possibly only available in his Imperfect C++ book.

Can I just make mention another implementation in case you are not already aware of it; Matthew Wilson's from his STLSoft libraries
http://www.stlsoft.org/doc-1.9/group__group____library____properties.html
Though the main documentation for it is possibly only available in his Imperfect C++ book.
Thanks for the link. I've been able to implement a better version than the first I posted. Now there are just TWO pointers to member functions per class, not per object. So every property has a pointer to an object and the pointers to member functions are shared. The properties can be virtual as well. You need to initialize non-trivial properties with this pointer. You can also initialize it with the this pointer and a value, but you don't need to initialize in the runtime parameters the getters and setters anymore.

Daniel Larimer wrote:
Best possible properties would have 0 per-instance overhead in either size or construction/destruction. Such a solution is possible and I hope to share it with the board soon. But put your mind to work and I am sure you can figure it out as I did in 30 minutes or less. It does require the use of macros however.
Boost.Test has RO, RW properties (no setter/getters) with 0 size overhead. Syntax: obj.prop for read access, obj.prop.value for write access. It has some pros and cons, and I am open for more general/powerful alternative. Gennadiy

What do you mean by: "the best possible c++ properties (implementation)." ? -Sid -----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Germán Diago Sent: Monday, March 01, 2010 1:24 PM To: boost@lists.boost.org Subject: Re: [boost] the best possible c++ properties (implementation). for trivial properties it's the same. But maybe in the future properties will be extended with some metadata. anyway, for trivial properties it's the same. _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
participants (9)
-
Christopher Jefferson
-
Daniel Larimer
-
Eoin O'Callaghan
-
Gennadiy Rozental
-
Germán Diago
-
James Porter
-
Pierre Morcello
-
Sid Sacek
-
Zachary Turner