Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I have a bunch "Property Sets" (which are simple structs containing POD members). I'd like to modify these property sets (eg: add a new member) at run time so that the definition of the property sets can be externalized and the code itself can be re-used with multiple versions/types of property sets with minimal/no changes.

For example, a property set could look like this:

struct PropSetA
{
    bool activeFlag;
    int processingCount;
    /* snip few other such fields*/
};

But instead of setting its definition in stone at compile time, I'd like to create it dynamically at run time. Something like:

class PropSet propSetA;
propSetA("activeFlag",true);  //overloading the function call operator
propSetA("processingCount",0); 

And the code dependent on the property sets (possibly in some other library) will use the data like so:

 bool actvFlag = propSet["activeFlag"];
 if(actvFlag  == true)
 {
   //Do Stuff
 }

The current implementation behind all of this is as follows:

class PropValue
{
 public:
    // Variant like class for holding multiple data-types
    // overloaded Conversion operator. Eg:
    operator bool()
    {
      return (baseType == BOOLEAN) ? this->ToBoolean() : false;
    }
    // And a method to create PropValues various base datatypes
    static FromBool(bool baseValue);
};

class PropSet
{

 public:
  // overloaded[] operator for adding properties
  void operator()(std::string propName, bool propVal)
  {
    propMap.insert(std::make_pair(propName, PropVal::FromBool(propVal)));
  }

 protected:
   // the property map
   std::map<std::string, PropValue> propMap;
};

This problem at hand is similar to this question on SO and the current approach (described above) is based on this answer. But as noted over at SO this is more of a hack than a proper solution. The fundamental issues that I have with this approach are as follows:

  • Extending this for supporting new types will require significant code change. At the bare minimum overloaded operators need to be extended to support the new type.
  • Supporting complex properties (eg: struct containing struct) is tricky.
  • Supporting a reference mechanism (needed for an optimization of not duplicating identical property sets) is tricky. This also applies to supporting pointers and multi-dimensional arrays in general.

Are there any known patterns for dealing with this scenario? Essentially, I'm looking for the equivalent of the visitor pattern, but for extending class properties rather than methods.

Edit: Modified problem statement for clarity and added some more code from current implementation.

share|improve this question
    
regarding stackoverflow.com/questions/235376/c-dynamic-class-dynamic-hack, can you give the reasons of your dissatisfaction with the existing answers? –  rwong Apr 18 '12 at 6:46
    
@rwong: I know it works, but like I said, I'm looking for something a little more refined. –  Bhargav Bhat Apr 18 '12 at 6:49
    
@BhargavBhat: if you define what you mean by "more refined", you will probably get better answers. Additionally, it would be helpful to know what issues you have with your current solution. Is persistence of the property sets an issue? Code duplication? Or do you want the change of the property sets to be possible at run time instead of compile time. Please clarify. –  Doc Brown Apr 18 '12 at 8:37
    
@DocBrown: The entire problem is about supporting property sets being modified at run time instead of compile time, so that these can be externalized and the existing code can be re-used with newer sets (with minimal changes). By "more refined" I mean that I'd like the solution to be structured for easy maintenance. The current approach is not very appealing because it involve many changes for even a (seemingly) simple change like supporting newer properties. Less/no code duplication would definitely be desirable, but I can live with some code duplication. –  Bhargav Bhat Apr 18 '12 at 8:49
    
Supporting newer types of properties would only be possible by defining a serialization to a known type (such as a string or a byte stream). Microsoft Structured Storage was one attempt to solve this universal problem, and you could have guessed the outcome: people are left with a binary file that can only be opened by "a COM class with GUID 0123-4567-89ab-cdef1023456..." and nobody know what DLL can decode that file. (The newer attempt is known as XML.) –  rwong Apr 18 '12 at 9:08
show 4 more comments

3 Answers

One suggestion is to make a PropValue a base type and BoolValue, IntValue, DoubleValue, ArrayValue, can be derived classes. Numbers could optionally be grouped into NumberValue and ArrayValue could be subclassed into VectorValue, DictionaryValue, etc.

This could help divide up the problems of defining traits as well as where to allow conversions of types.

I'm not seeing a complete picture of where you are handling dynamic types. It seems as though the consumer already knows or expects a bool in your example. So it is only syntactic sugar make an overloaded conversion rather than to call something like:

bool b_by_ref;
Error err  = Propset.GetBool("propname",&b_by_ref);

If you don't know or care about the type yet, just pass it as a PropValue* and let functions worry about the types internally in that algorithm.

void FooFunc (PropValue* p)
{
    DWORD id = p->GetTypeID();
    switch(id)
    {
        case INT_VALUE_TYPEID:   FooInt(p);
        case FLOAT_VALUE_TYPEID: FooFloat(p);
         .....
        default: Assert(0);
    }
 }
share|improve this answer
add comment

You need to get a real dynamic language, such as Lua or Python, to handle this kind of workload.

share|improve this answer
add comment

Well, AFAIU you want some kind of reflection, but to retain static type checking the reflection data must be available for template metaprograms. There are (or at least were) several efforts to implement such a library: Mirror C++ reflection utilities, Boost libraries for reflective programming (seem to be outdated). Take a look at them at least as source of inspiration. Also take a look at Boost.Fusion, it is a library for working with heterogeneous collections of data (tuples), which in turn can represent structs.

The simplest static reflection can achieved using a separate code generator which produces code like:

struct Foo {
  int a;
  double b;
};

// Types to identify struct members
namespace name_tags { struct a; struct b; }

// Reflection metadata for struct Foo
template<>
struct DataMembers<Foo> {
  typedef boost::fusion::result_of::make_map<
    name_tags::a,
    name_tags::b,
    Member<Foo, int>,
    Member<Foo, double>
  >::type type;

  type value;
};

DataMembers<Foo>::type
DataMembers<Foo>::value = 
  boost::fusion::result_of::make_map<
    name_tags::a,
    name_tags::b>(Member<Foo, int>(&Foo::a, "a"), 
                  Member<Foo, double>(&Foo::b, "b"));

Where Member class template is like:

template<typename S, typename M>
struct Member
{
  M S::* ptr;
  std::string name;

  Member(M S::* ptr, const std::string& name) : ptr(ptr), name(name) { }
};

Then you can use Boost.Fusion to apply a functor to all members of the class. You can use additional metafunctions to mark some members, e.g. as properties to process.

Iterating over members of Foo can be done as

boost::fusion::for_each(DataMembers<Foo>::value, ProcessMember());

struct ProcessMember
{
  void operator() (const boost::fusion::pair<name_tags::a, Member<Foo, int>>& mem) const
   {
     // ...
   }

  void operator() (const boost::fusion::pair<name_tags::b, Member<Foo, double>>& mem) const
   {
     // ...
   }

   // You can also provide a default case
   template<typename T>
   void operator() (const T&) const { }
};

Tag types name_tags::a and name_tags::b appear in the signatures of the operator() and allow to provide separate processing function for each member of Foo. If you add a member to Foo and update the reflection data (this should be automated) and forget to update processing functors application of those functions will fail to compile.

share|improve this answer
    
Reflection looks like it would be one possible solution, but I haven't really it considered much. I'd prefer something that would let me decouple dependency between a particular definition of a property set and the code that operates on it, meaning, older code should work with newer versions of property set definitions (as long as nothing major changes) and vice versa. I understand that this may not be possible all the time, but simple changes like adding a new field should not break code. –  Bhargav Bhat Apr 18 '12 at 9:31
    
You implement a very limited form of reflection that will suite your need (C++ have no reflection support anyways). –  Begemoth Apr 18 '12 at 9:36
    
Ah, you mean adding extra metadata and stuff so it can be used to provide hints to the main code. This will help distinguish between various versions of a given property set, but I don't see how it would let me extend the property set itself (i.e support adding a new member at runtime). –  Bhargav Bhat Apr 18 '12 at 9:42
    
I suggest using a code generator (the simple approach) or C preprocessor (the hard one) to generate this extra metadata. The complication of the build system seems to be a reasonable price to pay. –  Begemoth Apr 18 '12 at 9:52
    
Hmm... wouldn't having a code generator (writing, testing and making sure it doesn't do anything funny) be more effort that using the pre-processor? Also, I'm not really sure if the pre-processor can be used to provide all the meta-data that may be required. Anyways, I'll need to analyze this approach some more. –  Bhargav Bhat Apr 18 '12 at 9:54
show 1 more comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.