Interfaces - Under the hood

A ptr<T> is implemented in terms of a pair of underlying pointers:

Given one or more coercions from Circle to IShape within a given executable or library, the compiler generates a single static vtable of pointers to functions corresponding to the declared methods in the IShape interface. Each function takes a pointer to a Circle object as the first argument (i.e. in addition to the declared formal arguments).

The run time overheads of coercion are minimal - only requiring initialisation of the two pointers within the ptr<IShape>: the address of the circle object and the vtable pointer. This may only require two mov machine code instructions.

Generated code

The interface IShape defined as follows


$interface IShape
{
    float64 GetArea() const;
    float64 GetPerim() const;
};

is translated into the following C++ by the Xcpp front end:


struct IShape
{
    struct FnTable
    {
        float64 (*GetArea)(void const* _self);
        float64 (*GetPerim)(void const* _self);
    };
    IShape(void* _self, const FnTable* table) : m_self(_self), m_table(table) {}
    
    void AssignFrom(IShape& _rhs) { m_self = _rhs.m_self; m_table = _rhs.m_table; }
    void AssignFrom(IShape const& _rhs) const { const_cast<IShape*>(this)->m_self = _rhs.m_self; const_cast<IShape*>(this)->m_table = _rhs.m_table; }
    
    template<typename T> struct Stubs
    {
        static float64 GetArea(void const* _self) { return ((const T*)_self)->GetArea(); }
        static float64 GetPerim(void const* _self) { return ((const T*)_self)->GetPerim(); }
        static const FnTable& GetTable()
        {
            static const FnTable t =
            {
                &GetArea,
                &GetPerim
            };
            return t;
        }
    };
    template<typename T> void CoerceFrom(T* _rhs) { m_self = _rhs; m_table = &Stubs<T>::GetTable(); }
    template<typename T> void CoerceFrom(const T* _rhs) const { const_cast<IShape*>(this)->m_self = const_cast<T*>(_rhs); const_cast<IShape*>(this)->m_table = &Stubs<T>::GetTable(); }
    
    float64 GetArea() const { return m_table->GetArea(m_self); }
    float64 GetPerim() const { return m_table->GetPerim(m_self); }
    
    union
    {
        void* m_self;
    };
    FnTable const* m_table;
};