← Back to team overview

kicad-developers team mailing list archive

RFC: Testing completeness of implementation

 

Hi,

in my net_ties branch I'm adding a few additional classes that need to
be handled in all appropriate places. A pattern I've seen often in the
code (e.g. in the PAINTER classes) is

    void do_something(EDA_ITEM *item)
    {
        switch(item->Type())
        {
        case FOO_TYPE: // some pcbedit only type
            handle((FOO *)item);
            break;
        case BAR_TYPE: // another pcbedit only type
            handle((BAR *)item);
            break;
        default:
            // explicitly ignore to avoid warning
        }
    }

It is somewhat tedious to find all of these places, so I'm wondering if
there was a good way to make the compiler check that we caught all of them.

To me, this sounds like a use case for a Visitor pattern:

    class FOO;
    class BAR;

    class EDA_ITEM_VISITOR
    {
    public:
        virtual void Visit(FOO &) = 0;
        virtual void Visit(BAR &) = 0;
    }

    class EDA_ITEM
    {
    public:
        virtual void Apply(EDA_ITEM_VISITOR &) = 0;
    };

    class FOO : EDA_ITEM
    {
        virtual void Apply(EDA_ITEM_VISITOR &aVisitor) override
        {
            aVisitor.Visit(*this);
        }
    };

    etc.

The advantage of that pattern is that it maps a closed set of data types
to an open set of manipulators ("Visitor", e.g. tools), both ensuring
that every Visitor knows to handle every data object explicitly, and
avoiding the explicit cast in the process as well.

The downside is that it is a lot to type, especially as there is no good
way to indicate that a particular Visitor should decidedly ignore a
specific type.

We already have a Visitor pattern in the form of the INSPECTOR, which
could also be generalized this way.

Of course, the alternative is to have an abstract method in the base,
which also forces us to provide implementations for every derived class,
at the expense of bloating the base interface.

Are there maybe other methods that could be used to somehow check at
compile time that the implementation for a feature is complete?

Also, last but not least: in many places, we know the fully derived type
anyway, because our data model is not a classic tree where any node can
be anything -- rather, we usually have an explicit "list of tracks" or
"list of vias".

   Simon

Attachment: signature.asc
Description: OpenPGP digital signature