PrevUpHomeNext

Glossary

Objects
Mixins
Messages
Message priority
Multicast result combinators
Mutations

Here is a list of the major idioms, introduced by Boost.Mixin.

An object in terms of Boost.Mixin is an instance of the class boost::mixin::object. By itself it's not much more than an empty class. Its main purpose is to be a "container" of mixin instances. You can construct an empty object and then add or remove mixins from it via the object mutators.

The particular set of mixins in an object defines its type. An object mutation (adding or removing mixins) changes the objects type.

Now, "type", as mentioned above has nothing to do with the concept of type in C++. A boost::mixin::object naturally always is a boost::mixin:object. The object's type is a runtime concept, which is rarely (or never) used in a program. Instead, what's relevant for objects is their interface – which messages they implement.

The purpose of the object is not much different from the objects in the regular OOP style, you're probably used to. If you're developing a game, every "thing" in the game's world could be a boost::mixin::object. If you're developing a CAD system, every graphical element from a document could be one.

A mixin is a class used as a "building block" for an object. In Boost.Mixin a mixin doesn't have a specified type. It's the job of the library's users to define their own mixin types. There are several macros that you need to use in order to "tell" the library that one of your classes should be accepted as a mixin. The macros are non-intrusive and you don't need to change anything in existing code, to which you want to add Boost.Mixin.

Once you have mixins, you can combine them into objects. Adding or removing mixins to an object will internally instantiate them (via their default constructor) or destroy them. This means that a mixin instance is bound to an object instance. While it can be accessed via object::get, the mixin instance cannot be "removed" from an object, while also preserving it. Objects cannot share mixin instances.

You can think of mixins as the multiple parents of a class, when using multiple inheritance. Only in the case of Boost.Mixin, they can be added and removed dynamically, while preserving the state of the rest.

Messages in Boost.Mixin are a way of calling the methods of the mixins that comprise an object. You can think of messages as the methods of an object. Unfortunately C++ doesn't allow extension methods (as for example C# does) and to call an object's message, you need to write message(object, params...), instead of the much nicer object.message(params...).

The methods from your mixins, that will also become messages, cannot be inferred from the mixin class. There are macros that let you define a message's name and signature. Then, when defining the mixin (with its macro), you need to specify which messages it will implement. You will get a compilation error if the class, you've made into a mixin, doesn't have the method with the appropriate name and signature.

One key difference between messages and methods is the multicast mechanism, introduced by Boost.Mixin. For example consider the case when you add several mixins that implement the same message to an object and then call this message.

In the regular case one (based on priority) of those mixin will handle it. But if you define the message as a multicast, all of them will. This is very useful for cases such as information gathering (say with a message like trace (std::ostream& out))

A message priority can be used for both unicast and multicast messages. In both cases it's only relevant when multiple mixins in an object implement the same message. The priority is a signed integer with default value: 0.

For a unicast (regular) message, the mixin with the highest message priority will handle it. If multiple mixins have the same top priority, a runtime error will be triggered.

For a multicast message, the order of the mixins that handle it will be descending by priority. The order between mixins with the same priority cannot be defined. It's related to both global object initialization and how the unstable std::sort handles equal values.

When calling multicast messages, their return values are lost. Naturally, you can use an output parameter to collect those return values, but if you don't want to change existing methods, or if don't want to have the collection logic in them, the library provides a way to collect the return values externally.

This happens with multicast result combinators.

The library provides some common combinators, like boolean_or, boolean_and, and sum. It also allows you to easily create your own, for whatever purpose you need.

A mutation changes the type of an object. You have to use some kind of mutator to give type to the object.

Basically a mutation adds or removes mixins from an object.

A mutation rule is set globally applied to all mutations. A mutation rule may prevent a mixin to be added to an object or force one, even though the mutation wants to add it or doesn't mention it.

A very common mutation rule is to have mutually exclusive mixins, where when you add one, the other is removed.

The library offers some common mutation rules, but users can easily define their own custom ones.


PrevUpHomeNext