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

Basic usage questions #12

Closed
iwbnwif opened this issue Apr 28, 2016 · 6 comments
Closed

Basic usage questions #12

iwbnwif opened this issue Apr 28, 2016 · 6 comments
Assignees
Labels

Comments

@iwbnwif
Copy link

iwbnwif commented Apr 28, 2016

Hi, I would like to use Ponder to replace my home grown reflection that is currently implemented using nested macros and which suffers from all the debugging problems you mention in your blog :)

I need to warn you that I am relatively inexperienced in C++, so there may be some basic concepts I am missing.

  1. In a relatively complex project, which is split across several DLL, where is the best place to perform the binding (i.e. ponder::Class::declare<Person>("Person")...) ? I was wondering if I could create a composite container that holds my class and the binding within a static "Init" method. Thus, the binding will occur at startup and be already available whenever I instantiate the superclass.
  2. Is there a way for a subclass whose parent has been bound to Ponder to 'inherit' that binding? For example, if I were to subclass Person as Employee and Customer, do I have to rebind &Employee::name, &Employee::age, &Employee::speak, &Customer::name, &Customer::age, &Customer::speak etc. I tried to see if this possible without binding subclasses, but get a property age not found exception. With my macros I am using a lambda to extend the static bind map of the base class.
  3. I would like to be able to add extra meta data to properties for use when displaying the object, specifically "Hidden" and "Width". I think it would be convenient and efficient if I could do this as part of the binding call e.g. .property("name", &Person::name, visible, 200). I think this should be possible by subclassing ponder::UserProperty but would really appreciate if you could give me an example.

Lastly, just one little request ... can we have asserts instead of exceptions please ?!!!

Thanks for a great library, with a great licence 👍

@billyquith
Copy link
Owner

Hi there, we are all learning, all the time, so don't worry about that. I took on this project as a learning exercise in how to use new advanced C++11 features (and the web site is Jekyll and Bootstrap, another learning exercise!). And to that end it is still a work in progress. I have other projects on the go so will try and keep up to date with this one as well. The original project was not my work, this is a fork, so please forgive any misinformation I pass on.

Answers to questions:

  1. In a relatively complex project, which is split across several DLL, where is the best place to perform the binding (i.e. ponder::Class::declare<Person>("Person")...) ?

I mainly use static linking, as I'm a game developer, and some platforms (e.g. iOS) only allow static linking of libraries. Here, it is not such a problem, but when using DLLs you need to think about dependencies. If you have a "core" DLL, which everything else depends on, this would be the place to put Ponder. The binding could then be done anywhere as the objects created are stored in Ponder. Because of the DLLs you need to pay attention to deletion. I.e. Ponder has to delete anything it created, e.g.

const ponder::Class& metaclass = ponder::classByName("Person");
ponder::UserObject john = metaclass.construct(ponder::Args("John"));
metaclass.destroy(john);  // *** Ponder destroys the object it created

I was wondering if I could create a composite container that holds my class and the binding within a static "Init" method. Thus, the binding will occur at startup and be already available whenever I instantiate the superclass.

Ponder has automatic registration so you should be able to do this already. Look at the unit tests for examples.

  1. Is there a way for a subclass whose parent has been bound to Ponder to 'inherit' that binding? For example, if I were to subclass Person as Employee and Customer, do I have to rebind &Employee::name, &Employee::age, &Employee::speak, &Customer::name, &Customer::age, &Customer::speak etc.

Have a look at ClassBuilder::base source. Properties and functions (methods) are copied. You should be able to declare the common properties in the base and then base() of the subclass copies these to the subclass class declaration.

  1. I would like to be able to add extra meta data to properties for use when displaying the object, specifically "Hidden" and "Width". I think it would be convenient and efficient if I could do this as part of the binding call e.g. .property("name", &Person::name, visible, 200).

Could you not create a composite object Foo that has properties "name", "hidden", and "width", then bind this and include this object? Otherwise I think we're conflating two things: the binding (which is meta-data) and concrete data.

Lastly, just one little request ... can we have asserts instead of exceptions please ?!!!

Not so little, but perhaps should be allowed. Perhaps "policies" could be introduced for error handling. You might pass one in so that your app can deal with errors however it chooses?

@billyquith
Copy link
Owner

Might I ask why you want errors handled as asserts?

@iwbnwif
Copy link
Author

iwbnwif commented Apr 29, 2016

Thank you for your detailed answer. This is really helpful and now I feel I am able to do at least 80% of the things that I think I need to do.

Ponder has automatic registration so you should be able to do this already. Look at the unit tests for examples.

Perfect, in the unit tests I see the macro PONDER_AUTO_TYPE is used. I tried this as follows:

void RegisterPerson ()
{
    try
    {
        ponder::Class::declare<Person>("Person")
            .constructor<std::string>()
            .property("name", &Person::name)
            .property("age", &Person::age, &Person::setAge)
            .function("speak", &Person::speak);
    }
    catch (ponder::Error e)
    {
        std::cout << "Error: " << e.what() << std::endl;
    }   
}
PONDER_AUTO_TYPE(Person, &RegisterPerson)

It works if I first construct the metaclass with ponder::classByType but not with ponder::classByName.

Is there a way for a subclass whose parent has been bound to Ponder to 'inherit' that binding?

Have a look at ClassBuilder::base source.

Sorry, I don't know how I missed this. It works absolutely perfectly and does exactly what I wanted!

I would like to be able to add extra meta data to properties for use when displaying the object, specifically "Hidden" and "Width".

... Otherwise I think we're conflating two things: the binding (which is meta-data) and concrete data.

Sorry, my explanation wasn't very clear. Actually I meant that these are a sort of meta-data about the properties, the same as "writeable" etc. (but at a different level).

My plan is to use Ponder as a kind of data mapping layer where I have database tables like PERSON and fields like NAME varchar(50), AGE integer etc.

By using Ponder binding, I am able to have some generic functions for reading tables and converting them into vectors of 'intermediate class' objects. Most of the time these are then processed into other objects, but occasionally I would like to be able to throw up a quick dialog or list of the 'raw' intermediate objects.

It would be great if I can set meta data for a property that gives guidance on how to display that property (Ponder already has its name and type I can use for this purpose).

I thought it might be possible with tags, but these can only be attached to the metaclass and not to the properties. I can work around by having a static list that shadows the Ponder binding, but something like the following would be great:

ponder::Class::declare<Person>("Person")
    .constructor<std::string>()
    .property("name", &Person::name)
    .property("age", &Person::age, &Person::setAge)
    .propertyTag("name", "width", 100)
    .propertyTag("age", "hidden", true);

Thanks again, this really is a great library :)

@iwbnwif
Copy link
Author

iwbnwif commented Apr 29, 2016

It would be great if I can set meta data for a property that gives guidance on how to display that property (Ponder already has its name and type I can use for this purpose).

I thought it might be possible with tags, but these can only be attached to the metaclass and not to the properties. I can work around by having a static list that shadows the Ponder binding, but something like the following would be great:

ponder::Class::declare<Person>("Person")
    .constructor<std::string>()
    .property("name", &Person::name)
    .property("age", &Person::age, &Person::setAge)
    .propertyTag("name", "width", 100)
    .propertyTag("age", "hidden", true);

Thanks again, this really is a great library :)

After learning more, I now realise that exactly this is possible. IIUC .tag will affect the last registered property or the class if no properties have been registered yet. So it is simply a case adding a .tag to each property line:

void RegisterPerson ()
{
    ponder::Class::declare<Person> ("Person")
        .constructor<std::string>()
        .property("name", &Person::name).tag("width", 200)
        .property("age", &Person::age, &Person::setAge).tag("width", 100)
        .function("speak", &Person::speak);
}

Fantastic!!

@billyquith
Copy link
Owner

Looks like there is nothing to do for this.

@iwbnwif
Copy link
Author

iwbnwif commented May 17, 2016

Yes, sorry I should have closed it. Basically, Ponder does everything I want it to do!

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

No branches or pull requests

2 participants