Home

Awesome

Polypropylene - Let Your Objects Become Anything You Wish

Language Standard License Official documentation Language grade: C/C++ Total alerts Codacy Badge

<!--[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/3539/badge)](https://bestpractices.coreinfrastructure.org/projects/3539)-->

Polypropylene is an embedded domain-specific language (EDSL) for C++17 to model separation of concerns at any granularity, from single objects to large frameworks. It allows defining objects dynamically by composition of properties. Properties add state and functionality to objects similar to mixins but are composed during runtime.

Polypropylene started as an Entity-Component System (ECS) but grew more general and flexible. An ECS is a design pattern mostly used in video game engineering where objects are required to change behaviour and shape frequently and arbitrarily. Thereby, an object (i.e., an Entity) is purely defined as a composition of individual components. We refer to Components as Properties to emphasize that Polypropylene is not limited to but can be used as an ECS. You may find a detailed description of ECS in the ecs-faq.

During development several issues arose that were not addressed by existing ECS' so far. Most prominently, I was missing an ECS which allows you to write the style you know: object-oriented and not data-oriented. To not lose benefits of a data-oriented design, Polypropylene abstracts memory management in a backend, while allowing to program in an object-oriented fashion.

Below you find a small excerpt on how to define entities and properties in Polypropylene:

class Pizza : public PAX::Entity<Pizza> {};

class TomatoSauce : public PAX::Property<Pizza> {
    PAX_PROPERTY(TomatoSauce, PAX_PROPERTY_IS_CONCRETE)
    PAX_PROPERTY_DERIVES(PAX::Property<Pizza>)
    PAX_PROPERTY_IS_SINGLE
    
public:
    unsigned int scoville = 0;
};

class Cheese : public PAX::Property<Pizza> {
    PAX_PROPERTY(Cheese, PAX_PROPERTY_IS_ABSTRACT)
    PAX_PROPERTY_DERIVES(PAX::Property<Pizza>)
    PAX_PROPERTY_IS_MULTIPLE
    
    PAX_PROPERTY_DEPENDS_ON(TomatoSauce)
    
    virtual ~Cheese() = 0;
};

class Mozzarella : public Cheese {
    PAX_PROPERTY(Mozzarella, PAX_PROPERTY_IS_CONCRETE)
    PAX_PROPERTY_DERIVES(Cheese)
    PAX_PROPERTY_IS_SINGLE
};

void main() {
    Pizza pizza;
    pizza.add(new TomatoSauce()); // otherwise we cannot add cheese
    pizza.add(new Mozzarella());

    // no dynamic_casts here
    pizza.get<TomatoSauce>()->scoville = 3000; // put Tabasco in ;)
    Mozzarella * mozzarella = pizza.get<Mozzarella>();
    const std::vector<Cheese*>& cheeses = pizza.get<Cheese>(); // There might be multiple cheese types apart from mozzarella, so we get a vector.
}

Opposed to existing Entity-Component Systems and Dynamic Mixin Implementations, Polypropylene offers the following features:

Apart from that, Polypropylene is:

Polypropylene further contains the following features:

<!-- - **Systems**: Systems can be used for any kinds of (global) behaviour. In entity component systems, they are used to manage and execute behaviour on properties. For this reason, `PropertyOwningSystems` contain all properties of a given type by managing their allocation with a pool allocator. That allows for fast iteration over all properties of a certain type. ```C++ // The system will register itself as the allocator to use for TomatoSauce. // Hence, it needs to be created before creating any TomatoSauce. PropertyOwningSystem<Pizza, TomatoSauce> tomatoValley; Pizza p; p.add(new pax_new(TomatoSauce)()); for (TomatoSauce * t : tomatoValley) { // Here each active TomatoSauce that was allocated with the pizza's allocator can be found. } ``` -->

Further Utilities

Customisations for Compile Time Minimisation

To obtain reflection information, we frequently use templates and macros. We made certain features, such as loading from json files, optional such that you do not have to compile code that you do not need. The following cmake options allow compile time customisation. By default, all options are activated (set to ON):

Code Examples

The small pizza example from the top of this readme file can be found in examples/pizzasnippet/. It is exemplified in further detail in examples/pizza/. We suggest heading to the main.cpp for getting an entry point and quick start.

An extensive example for the usage of Polypropylene can be found in the game engine PaxEngine3. In PaxEngine3, both Game Objects and Game Worlds are implemented as Entities of Polypropylene.

For further instructions, please have a look at our wiki.

Future Plans and Open Issues

Feedback

I welcome any constructive critism, questions, and bug reports. Feel free to open issues or pull-requests here on GitHub. :blush:

Naming Conventions and "Where does the name come from?"

Polypropylene is a backronym for POLYmorphism aware PROPertY Library for mutablE dyNamic objEcts. As this is a rather long name, we kept our short and memorisable inter-project namespace PAX.

Related Work

If we could not get your interest in using our library, there are other great projects which you might want to check out.

Entity Component Systems:

Dynamic Mixins:

More interesting projects can be found in the ecs-faq. Did I forget your library? Please open an issue or pull-request!

Are You Hungry For Pizza :pizza: Now?

At least we are ... :yum: