Boost logo

Boost :

Subject: [boost] [interfaces] Boost Interface Library (2004?)
From: Daniel Larimer (dlarimer_at_[hidden])
Date: 2011-02-06 15:07:16


I recently ran across the unofficial Boost Interface Library (http://www.coderage.com/interfaces), but it appears that it is was never adopted nor much discussed since I joined this mailing list.
Boost.Interfaces provides a macro-based Interface Definition Language (IDL) which can be used to define C++ class types called interfaces. An interface is a lightweight value type associated with a set of named function signatures. An interface instance can be bound at runtime to any object which implements the interface, i.e., to any object of a type with accessible non-static member functions having the same name and signature as the set of functions associated with the interface. The functions of the bound object can then be invoked through the interface instance using the �dot� operator. Binding is completely non-intrusive: the object's type need not declare any virtual functions or derive from any particluar base class.

Interfaces were described in a September 2004 C/C++ Users Journal article by Christopher Diggins.

After looking through the library I concluded that I did not like how it was implemented. Too many macros, unnatural syntax. I guess few people liked it enough for it to be kept up to date (6+ years old now). I have also looked at the Boost Mirror library which provides reflection of just about everything at the expense of some nasty macros and no clear path toward defining dynamic interfaces based upon the reflected type information.

I think the goal of the interface library should be a more flexible/powerful version of "boost::any" that allows you to define the interface of the object stored in the 'any'. In this way it takes type erasure to a new level.

That said, I have a need for developing an interface library that abstracts the differences between direct pointer access, RPC, and asynchronous inter-thread communication. So I have developed and tested a new 'api' for defining interfaces with the hope that it would be considered worthwhile for boost.

Goals / Non-Goals
        1) Define Interfaces in Natural C++ Syntax
        2) Provide the ability to define 'dynamic' implementations of an interface for calling RPC, scripting language interface, etc.
        3) Objects that implement 'interfaces' should be long-lasting 'actors' where overhead of creating/copying/destroying the interface along with any memory usage is of secondary importance to the ease of defining dynamic interfaces and achieving 'type erasure'.
        4) Ideally each member of an interface is a function object that can be bound to anything.

I am interested in feedback on what the API/features should be of a generic interface library to improve upon BIL. Should the interface definition classes be in a namespace such as idl_definition or should the BOOST_IDL_INTERFACE macro place the interface type in an 'idl' namespace?

Example:

namespace idl_definition {
    struct SomeBase
    {
        // these methods need not be implemented anywhere as they are never called.
        std::string name()const;
    };
    struct Shape : public SomeBase
    {
        double area(int);
        std::string type();
        std::string my_mem;
    };
}
           
BOOST_IDL_INTERFACE( SomeBase, BOOST_PP_NIL,
    (name)
)
BOOST_IDL_INTERFACE( Shape, (SomeBase,BOOST_PP_NIL),
    (area)
    (type)
    (my_mem)
)
       
class print_api_visitor : public boost::idl::visitor<print_api_visitor>
{
    public:
       template<typename InterfaceName, typename M>
       bool accept( M& m, const char* name )
       {
            std::cerr << boost::idl::get_typestring<InterfaceName>::str() << "::" << name << " "
                      << boost::idl::get_typestring<typename M::signature>::str() << (M::is_const ? "const" : "") << std::endl;
            return true;
       }
};

class Circle
{
    public:
    std::string name()const{ return "CircleName"; }
    double area(int v) { return v*3.1415; }
    std::string type() { return "circle"; }
    std::string my_mem;
};
    

int main( int argc, char** argv )
{
    boost::shared_ptr<Circle> c(new Circle());
    Shape s = c;//Circle(); //new Circle();
    s.my_mem = std::string("HelloWOrld");
    std::string tmp = s.my_mem;
    std::cerr<<"type: "<<s.type() << std::endl;
    std::cerr<<"area: "<<s.area(3) << std::endl;
    std::cerr<<"area: "<<*s.my_mem << std::endl;
    
    std::cerr<< "9*pi = "<<boost::idl::make_delegate( c.get(), Shape::__idl__area::get_member_on_type<Circle>() )(9) << std::endl;
    std::cerr<< "my_mem = "<< c.get()->*Shape::__idl__my_mem::get_member_on_type<Circle>() << std::endl;
    std::cerr<< "my_mem = "<< c.get()->*s.my_mem.get_member_on_type<Circle>() << std::endl;

    std::cerr<<"print api!\n";
    print_api_visitor papi;
    papi.start(s);

    Circle* c2 = new Circle;
    c2->my_mem = "Circle2!!!";
    boost::idl::set_delegate_visitor<Circle> sd(c2);
    sd.start(s);

    std::cerr<<"c->area: "<< *s.my_mem << std::endl;

    return 0;
}

Here is an example of the visitor used to setup the delegate:

    template<typename T>
    class set_delegate_visitor : public boost::idl::visitor<set_delegate_visitor<T> >
    {
        public:
           set_delegate_visitor( T* self = 0)
           :m_self(self){}
                                                                                                                                                             
           template<typename InterfaceName, typename M>
           bool accept( M& m, const char* name )
           {
                m.set_delegate( m_self, M::template get_member_on_type<T>() );
                return true;
           }
       private:
           T* m_self;
    };

Output
====================
type: circle
area: 9.4245
area: HelloWOrld
c->area: HelloWOrld
sizeof(s): 120
9*pi = 28.2735
my_mem = HelloWOrld
my_mem = HelloWOrld
print api!
SomeBase::name std::string()const
Shape::area double(int32_t)
Shape::type std::string()
Shape::my_mem std::string
c->area: Circle2!!!


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