Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to uniformly implement two-way conversion without code repetition?

I have two big C structures used in a C legacy code, and I need to convert from one to another, and the other way around. Something like this :

#include <iostream>

struct A {
    int a;
    float b;
};
struct B {
    char a;
    int b;
};

struct C {
    A a;
    B b;
};

struct D {
    int a;
    char b;
    float c;
};

void CtoD( const C& c, D &d ) {
    d.a = c.a.a;
    d.b = c.b.a;
    d.c = c.a.b;
}
void DtoC( const D &d, C& c ) {
    c.a.a = d.a;
    c.b.a = d.b;
    c.a.b = d.c;
}

int main()
{
    C c = { { 1, 3.3f }, { 'a', 4 } };
    D d = { 1, 'b', 5.5f };

#if 0
    CtoD( c, d );
#else
    DtoC( d, c );
#endif

    std::cout<<"C="<<c.a.a<<" "<<c.a.b<<" "<<c.b.a<<" "<<c.b.b<<std::endl;
    std::cout<<"D="<<d.a<<" "<<d.b<<" "<<d.c<<std::endl;
}

Functions CtoD and DtoC are doing the same thing, but in opposite direction. Changing one structure requires changing both of them.

To minimize possibility of an error, and to avoid repetition, I would like to implement some kind of mapping, where I define the connections only once, and then I copy one value to another. This way, only one change is needed if a structure changes.

So, the question is : how to do it? Is there perhaps a design pattern I could use?


My real structures have hundreds of fields. The above is just simplified example.

like image 386
BЈовић Avatar asked Oct 15 '13 09:10

BЈовић


1 Answers

In your literal example, I don't think it's worth the hassle. Just write tests so that you ensure your conversions work well.

In your real code, if your structs have "hundreds of fields", your structs may be badly designed. Maybe they should be composed of smaller objects. I've never designed anything which required hunderds of fields in exactly the same struct object - instead, these fields allowed some kind of classification so that they could be treated in smaller bunches.

Since your code is legacy and you don't want to rewrite it, just write tests for your conversions functions, as I said above for the example.

Well tested code is no longer legacy code. Legacy code is basically code for which you don't have automated tests.

If rewriting it is not an option, testing it is a must.

About the cost of testing it "both ways", Idan Arye's comment below says everything:

Since the conversion is symmetric, testing it both ways is not that much more work than testing it one way. All you need to do is init two structs - C c and D d - and set them to be the converted versions of each other. Then you just have to check that CtoD(c)==d and DtoC(d)==c (or use comparison functions if you happen to have them defined). The big work here is initializing c and d - but you would have to do that anyways if you wanted to test one way conversion, so adding the test for the other way is very cheap.

like image 58
Daniel Daranas Avatar answered Oct 12 '22 05:10

Daniel Daranas