Boost logo

Boost :

Subject: [boost] Interest in runtime concepts library.
From: Germán Diago (germandiago_at_[hidden])
Date: 2011-02-06 12:15:26


Hi all. I'm implementing a framework to use runtime concepts for a
project of myself.
I would like to know the interest in that library. For now, I have a
proof of concept working.

The goal of the library, for now, is to be able to use objects of
differente types without
having any inheritance requirements and being nonintrusive. The code
has my own standards
for naming conventions, but that can be changed later when I have
something ready for
consumption.

Now, to the metal. First, an example. Imagine we have two types of
Devices. One of them
is a DeviceC (which stands for Device Concept) and another, more
refined one is PlugableDeviceC.

With my library I can write something like this to create types that
can hold classes that model both concepts:

//Base concept
class IDeviceC {
public:
        virtual std::size_t getCapacityInMB() const = 0;
};

template <class T>
class DeviceCModel : public MovableModelBase<T>, public IDeviceC {
public:
        IMPLEMENT_MODEL_DEFAULT_MEMBERS(DeviceCModel)

        virtual std::size_t getCapacityInMB() const {
                return this->getData().getCapacityInMB();
        }
};

//This is a DeviceC runtime concept
typedef MovableConceptBase<IDeviceC, DeviceCModel> DeviceC;

//Refined concept
class IPlugableDeviceC : public IDeviceC {
public:
        virtual void onOpen() = 0;
        virtual void onRemove() = 0;
};

template <class T>
class PlugableDeviceCModel : public IPlugableDeviceC, public
MovableModelBase<T> {
public:
        IMPLEMENT_MODEL_DEFAULT_MEMBERS(PlugableDeviceCModel)

        virtual void onOpen() {
                return this->getData().onOpen();
        }

        virtual std::size_t getCapacityInMB() const {
                return this->getData().getCapacityInMB();
        }

        virtual void onRemove() {
                return this->getData().onRemove();
        }
};

//Create concept class that refines DeviceC, The 3rd parameter is the
concept it refines
typedef MovableConceptBase<IPlugableDeviceC, PlugableDeviceCModel,
DeviceC> PlugableDeviceC;

Now we have two classes, DeviceC and PlugableDeviceC which can be used
to hold any type that models
that concept.

Now, in my main program I implemented two classes, one of them
modeling a PlugableDeviceC and another one
modeling DeviceC:

class LegacyDevice : NonCopyable {
public:
        //This class models DeviceC concept
        typedef DeviceC ModelOfType;

        std::size_t getCapacityInMB() const {
                return 10;
        }
};

class IpodDevice : NonCopyable {
public:
        //This class models PlugableDeviceC concept
        typedef PlugableDeviceC ModelOfType;

        void onOpen() {
                std::cout << "Opening Ipod device" << std::endl;
        }
        void onRemove() {}

        std::size_t getCapacityInMB() const {
                return 32 * 1024;
        }
};

operator-> is used to access the interface functions in an easy way. I
also coded a Ref<SomeConcept> type
which behaves like a C++ reference. It has implicit conversion to Base
concepts. You can also cast to different
concept types (more refined, like downcasting with inheritance). The
return of a casting with a concept as a parameter
always returns a Ref<SomeConcept>. You can use that reference with
operator-> to access its members (in C++
I can't overload operator. , so I used operator-> to delegate
functions). If you cast to a non-concept type (a concrete one)
it will return a regular c++ reference. The result is something like
this for now:

int main(int argc, char * argv[]) {
        std::vector<DeviceC> devices;
        IpodDevice ipod;
        LegacyDevice legacy_device;

        devices.push_back(move(ipod));
        devices.push_back(move(legacy_device));

        //getCapacityInMB() is a function that you can use for DeviceC
        for (auto & device : devices) {
                std::cout << device->getCapacityInMB() << std::endl;
        }

        /*This is a downcast. Although a class that models plugable device is being
         * held inside a DeviceC, you can downcast to its right (most-derived) concept
         */
        Ref<PlugableDeviceC> plugable_device = devices[0].castTo<PlugableDeviceC>();

        //Implicit conversion to base concept
        Ref<DeviceC> device = plugable_device;

        //This is a function that just exists for PlugableDeviceC types.
        plugable_device->onOpen();
}

There's still quite a bit of work to do:

-Implement a Ptr<Concept> that behaves like a reference but that accepts null.
-Make possible that a class models more than one concept.
-Lots of testing.
-Look at how runtime concepts behave with shared_ptrs to make a
sensible decision about
if a custom class like Ref should be implemented or a shared_ptr is good enough.

Opinions are welcome. The code is attached. Tested with g++ trunk in linux.




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