Boost logo

Boost :

Subject: Re: [boost] [mixin] Introducing a new library.
From: Borislav Stanimirov (b.stanimirov_at_[hidden])
Date: 2013-02-01 16:56:31


On 02/01/2013 01:55 PM, Matus Chochlik wrote:
> Hi,
>
> On Wed, Jan 30, 2013 at 8:53 PM, Borislav Stanimirov
> <b.stanimirov_at_[hidden]> wrote:
>> Hello,
>>
>> Boost.Mixin is a library I'm developing with the idea to someday submit it
>> to Boost.
>>
> [..8<...]
>
> This library certainly looks interesting. It reminds me of the Crystal
> Entity Layer
> from the Crystal Space engine. Are you familiar with it, and if so could
> you compare the two ?
>

I'm not familiar with it, but I took a look at it and here's what I can
say (correct me if im wrong). CEL is a clasic interface entity-component
system. It's entities are bags of interfaces to components. Here's how
such a system works (the following example is not their exact code, but
I think the idea behind it is almost identical)

// ============= creation =============
entity e;
e.add_component<iserializable>(new text_file_serializer);
// text_file_serializer definition must be included for this line

e.add_component<irendering>(new d3d_rendering);
// d3d_rendering definition must be included for this line

// both iserializable and irendering are derived from icomponent
// this provides children with get_owning_object, generates ids... etc

// ============= use =============

e.get_component<iserializable>()->serialize();
// iserializable definition must be included for this line

e.get_component<irendering>()->render();
// irendering definition must be included for this line

// ============= mutation =============

e.change_component<irendering>(new opengl_rendering)
// opengl_rendering definition must be included for this line

Now, a similar piece of code could be written with Boost.Mixin. However
this is not the preferred way of using the library. First. It is
non-intrusive. Your mixins are your regular classes. They don't need to
derive from anything. You use macros to identify them as components, and
you don't need to change the class code.
Second you don't need to bind a series of messages to a predefined
interface. The messages are simply stand-alone functions and mixins can
choose whether to implement them or not. You could even hide the
visibility of some implementations with others.

Here is a Boost.Mixin example

// ============= creation =============
object o;
mutate(o)
     .add<text_file_serializer>()
     .add<d3d_rendering>();
// only mixin declarations are required for the previous lines
// basically here nothing is known about both classes except their
// forward declarations

// ============= use =============

serialize(o);
// only the message declaration is needed for the previous line
// for all we know the rendering mixin might implement it

render(o);
// again only the message is known here

// ============= mutation =============

mutate(o)
     .remove<d3d_rendering>()
     .add<opengl_rendering>();
// same as creation

// something cool
// say we have a mixin which is defined like that
class stub_rendering
{
     public: void render() {}
};
BOOST_DEFINE_MIXIN(stub_rendering, priority(10000, render_msg);
// note the high priority chosen for render
// this means that any mixin implementing the same message with
// lower priority (default is 0) will have its implementation hidden
// by this

mutate(o).add<stub_rendering>();

render(o);
// it doesn't matter for the previous call if the object has
// d3d or opengl rendering, their render-s will be overriden
// by the method in stub_rendering, and nothing will happen
// (well as long as their priorities for render are lower than 10000)

One thing that CEL supports but Boost.Mixin doesn't (yet) is the ease of
mutating entities, without caring for component consistency. See how in
order to substitute the `d3d_rendering` with `opengl_rendering` the user
didn't need to care what's already there. It could've been say,
`software_rendering`. In Boost.Mixin right now in order to remove mixins
from the object, you need to know exactly which one you need to remove.
So the code from above could've been more like:

object_transformer transformer(o);

if(o.has<d3d_rendering>()) transformer.remove<d3d_rendering>();
else if(o.has<software_rendering>())
transformer.remove<software_rendering>();

transformer.apply(); // does the actual mutation

This is pretty incovenient. But good news! In no more than two weeks
I'll introduce the notion of mutually-exclusive mixins. I'm not sure of
the exact code yet, but it will be something similar to this:

mutually_exclusive_mixins mem_rendering;

mem_rendering.add<d3d_rendering>();

mem_rendering.add<opengl_rendering>();
// any mutation occuring after the execution of the previous line,
// will automatically remove one mixin if the mutation
// tries to add the other

mem_rendering.add<software_rendering>();
// any mutation occuring after the execution of the previous line,
// will automatically remove any two of the three mixins
// if the mutation tries to add the third

As a whole, as far as entity-component systems go, CEL seems basic.
However, they do have lots of other features. The engine comes with a
big number of predefined components, which is very useful, while
Boost.Mixin is just a bare system. It doesn't offer any mixins.

The most important (and huge) thins is that they have reflection and
script integration.
While there are plans for Boost.Mixin to have those too, thay are... to
put it mildly... set for the distant future.

-- Borislav


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk