Menu

CtorParameters

Anonymous

Notes on ctor parameters of wallaroo managed classes

This page is obsolete:

Attributes have been added to wallaroo.


Introduction

Currently (v. 0.5 - april 2014), the main limit of wallaroo is the maximum number of constructor parameters a managed class can have (i.e. two). Besides, a class defined in a dynamic library must have a constructor without parameters.

Removing this limit could be the last activity before finally bring the release number to 1.0

This wiki page contains some notes about this topic.

The problem

Currently, wallaroo only manages classes (parts) having constructors with 0, 1 or 2 parameters. Besides, the limit for classes defined in shared libraries is stricter: they must have a default constructor.

This limit is due to the following problems:

  • some wallaroo classes are parametrized on the two constructor parameters, with specialization for the void case;
  • the creation mechanism of wallaroo is based on template: in particular, it needs the class name (string) and the type of the two constructor parameters (template parameters, possibly void). In a configuration file you need to specify all these three piece of information. No problem for the class name (it's a string!), but the parameters must be converted from strings to types, providing all the possible permutations (see file ptreebasedcfg.h). Incrementing the parameters number would produce an exponential increment of the combinations.
  • shared libraries export a list of descriptors of all the classes defined inside. The descriptors have a pointer to the class factory function: one must decide one single function signature for all classes. I choosed to fix it to have no parameters.

The current code has also some advantages:

  • you can declare class constructors in the traditional way (no extra verbosity)
  • you can invoke Catalog::Create directly with the parameters of the object you want to create (no extra verbosity)

Solution requirements

Wallaroo needs a mechanism to pass an arbitrary number of parameters when constructing an object (a part in wallaroo parlance). The solution should have the following properties:

  1. it must work with both the construction methods (by code and by configuration file),
  2. it must work with both the class declaration methods (single executable and shared libraries),
  3. it should be compatible with the current code,
  4. it should not require boost libraries in those cases where now are not needed
    (the last two points are just preferences).

Solutions

Here are explained a list of candidate solutions.

Parameters table

We can pass a table of named parameters to the ctor (e.g.: std::map< std::string, boost::any > ). This means:

  • we should do more work to fill the map and to extract the parameters
  • we give up the requirement #4 (we need to use boost::any everywhere), unless we develop our own version of any.

To simplify the usage, we could provide a ParameterSet class that incapsulate the map, hiding the use of any:

E.g. (class definition)

class Foo : public Part
{
public:
    Foo( const ParameterSet& pars );
    ...
private:
    std::string color;
    int number;
    ...
};

WALLAROO_REGISTER( Foo ) // register this class

Foo::Foo( const ParameterSet& pars ) :
    color( pars[ "color" ] ),
    number( pars[ "number"] )
{
}

E.g. (usage)

Catalog catalog;

ParameterSet pars;
pars[ "color" ] = "red";
pars[ "number" ] = 42;
catalog.Create( "foo", "Foo", pars );

When using a configuration file (xml, json), we have two options:

  • specify in the configuration file the type of each parameter (so that we can insert the right type in the any object)
  • don't specify the type of the parameters: in this way, we have to store strings inside the parameter table, and then convert it to the right type inside the constructor (who else know the type of the parameters?!)

Const attributes injection

We can use a mechanism similar to wallaroo::Collaborator to add const attributes to the class.

This way, an object would be created without parameters, then its const attributes filled using an injection mechanism imilar to the one used for dependencies.

E.g. (class definition)

class Foo : public Part
{
public:
    Foo();
    virtual ~Foo();
    ...
private:
    Collaborator< Bar > bar;
    Attribute< std::string > color;
    Attribute< int > number;
};

WALLAROO_REGISTER( Foo ) // register this class

Foo::Foo() :
    bar( "b", RegistrationToken() ),
    color( "color", RegistrationToken() ),
    number( "number", RegistrationToken() )
{
}

E.g. (usage)

Catalog catalog;

catalog.Create( "foo", "Foo" );
catalog.Create( "bar", "Bar" );

// option #1
catalog[ "foo" ][ "color" ] = "red";
catalog[ "foo" ][ "number" ] = 42;

wallaroo_within( catalog )
{
    use( "bar" ).as( "b" ).of( "foo" );

    // option #2
    set( "color" ).of( "foo" ).to( "red" );
    set( "number" ).of( "foo" ).to( 42 );
}

// check if all collaborators are wired
assert( catalog.IsWiringOk() );
// check if all attributes are set
assert( catalog.AreAttributesOk() );

// calls the method Init of each parts
// maybe it would be better to call IsWiringOk 
// and AreAttributesOk inside Catalog::Init() ?
catalog.Init();

Is this feasible in the first place?

Please note that in traditional programming the constructor parameters are possibly used inside the body of the constructor; with this approach, instead, the attributes are not yet set during the parts constructor execution. A possible workaround for this issue is to provide some kind of Part::Init method where doing the actual part setup work that require the attributes. A Catalog::Init method could call Part::Init for each part contained.

When using a configuration file (xml, json), we still have two options:

  • specify in the configuration file the type of each parameter (so that we can insert the right type in the statement set( "attribute_name" ).of( "part_name" ).to( object ););
  • don't specify the type of the parameters: the function to can take a string and the conversion to the right type can be operated inside the Attribute<T> class (that knows the actual type - T).

Other solutions?

Suggestions are welcome :-)


Related

Wiki: Attributes
Wiki: TableOfContents

Discussion

  • Anonymous

    Anonymous - 2014-04-28

    Originally posted by: fabien.c...@gmail.com

    Good start :)

    Remark 1:

    If you dont want a dependancy to boost, may be you could use a minimal "any" class like that : http://stackoverflow.com/questions/4988939/how-do-boostvariant-and-boostany-work

    Remark 2:

    The other solution could be to wrap all basic types (int, long, double, string, etc.) as a Plug itself, or keeping the Attribute concept. So instead of

    use( "bar" ).as( "b" ).of( "foo" );

    one could write :

    use( "red" ).as( "color" ).of( "foo" ); or use( 42 ).as( "number" ).of( "foo" );

    This implied to modify a bit the use func.

    I am wondering if there is a good reason to adopt the pair Attribute/set...of...to instead of extending the Plug concept ...

     
  • Anonymous

    Anonymous - 2014-04-28

    Originally posted by: fabien.c...@gmail.com

    last thing : I dont understand the Device::Init usage ... Could you be more specific?

     
  • Anonymous

    Anonymous - 2014-04-29

    Originally posted by: fabien.c...@gmail.com

    "I am wondering if there is a good reason to adopt the pair Attribute/set...of...to instead of extending the Plug concept ... ".

    I really think the Plug and Attribute concepts are different : Attribute belongs to the instance while Plug belongs to the usage of the instance.

     
  • Anonymous

    Anonymous - 2014-04-29

    Originally posted by: daniele....@gmail.com

    I expanded a bit the explanation of Device::Init. Hope it's more clear, now.

    If we go for solution #1 I'll develop a wallaroo version of any, thanks.

    Yes: I guess Plug and Attribute are different concepts... I really wouldn't like to create confusion (read: bugs :-) in the mind of the user. Anyway: the syntax is important but now I'd prefer to focus on the choice of the best solution, whether they're feasible, whether there is any problem in the implementation (e.g. with shared libraries usage) and so on...

     
  • Anonymous

    Anonymous - 2014-04-29

    Originally posted by: fabien.c...@gmail.com

    1- You are right about the Init function.

    2- I am playing right now with wallaroo and I dont have enough perspective for #1 or #2 solution.

    The input ParameterSet? as argument is good because it is very easy to manipulate and changing its content. This can be also a trap : weak-typing is the beginning of the end ...

    Attribute injection is heavy but the AtttributeOk?() check is a good structural check. I have a little preference for this one but you're the leader, your call :)

    Thanks anyway

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.