Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consistent behaviour regarding const objects #66

Open
Weeena opened this issue Jan 4, 2017 · 1 comment
Open

Consistent behaviour regarding const objects #66

Weeena opened this issue Jan 4, 2017 · 1 comment

Comments

@Weeena
Copy link

Weeena commented Jan 4, 2017

Consider a simple class with a getter and a setter

class MyClass
{
public:
    MyClass() : i_(0) {};
    int Getter() const { return i_; };
    MyClass& Setter(int i) { i_ = i; return *this; };
private:
    int i_;
};

that is declared to ponder

PONDER_TYPE(MyClass)

ponder::Class::declare<MyClass>("MyClass")
    .constructor()
    .property("Object", &MyClass::Getter, &MyClass::Setter);

If I have a const reference to an object of this class I am not allowed to modify it. With a const ponder::UserObject, on the other hand, modifying this object is possible:

const MyClass myClassObject;
const MyClass& refToMyClassObject = myClassObject;
refToMyClassObject.Setter(41); // COMPILATION ERROR! Not allowed to modify a const object
const ponder::UserObject myClassUserObject(refToMyClassObject);
myClassUserObject.set("Object", 42); // No compilation error, const object gets modified
assert(refToMyClassObject.Getter() == 42);

With all that const around that behaviour may be counterintuitive.

From my point of view, what possibilities would exist to accomplish a consistent behaviour:

1. Do not allow to make a ponder::UserObject from a const object

Reasoning: WYSIWYG (= what you see [in the interface] is what you get). This would mean that in ponder e.g.

    template <typename T>
    UserObject(const T& object);

would have to be changed to

    template <typename T>
    UserObject(T& object);

I guess this is not a very attractive option. If you like to reflect on a const object (e.g. to serialize it) and plan to only read its properties, you would have to apply a const_cast which is always something you like to avoid.

2. Allow a ponder::UserObject to be made from and to modify a const object consequently

Reasoning: Reflection is something that exceeds the normal possibilities of a language.

In this case, ponder's interface could essentially stay as it is now. To be consequent, though,

inline UserObject Class::getUserObjectFromPointer(void* ptr) const
{
    return m_userObjectCreator(ptr);
}

should in my opinion then be changed to

inline UserObject Class::getUserObjectFromPointer(const void* ptr) const
{
    return m_userObjectCreator(ptr);
}

Of course, it would also have to be emphasized in the documentation that with ponder's reflection you are able to modify const objects.

3. Have a ponder::UserObject support a read-write as well as a read-only mode

Reasoning: Once againg WYSIWYG. With this option, if you make a ponder::UserObject from some const object this would then be the read-only mode where you would not be allowed to modify this object.

I guess this would be the best option, yet associated with the most effort.


What do you think? Was ponder intentionally designed for option 2? In any case, option 2 is what ponder now supports. Hence I would be happy if you would approve the modification I suggest in option 2 (which would avoid the const_casts that I now need to reflect on objects for which I have a const void*.)

@billyquith
Copy link
Owner

It's a tough one and perhaps needs a different angle. I did think about refactoring UserObject and making it policy based. I.e. you would pass it the traits that you would like it to have, like class member declarations can currently.

A UserObject currently owns a data holder, so two objects are allocated. This might be collapsed into one for some purposes. I never really got past that stage though.

In the case of const, as you mention, because of language constraints, perhaps opaque handles need to be used and a similar API to the runtime calling.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants