Во время работы над одним из проектов, старший коллега порекомендовал мне скопировать код небольшой функции из другого, уже готового проекта. Я глянул туда (заранее настраиваясь не особо расстраиваться от "копи-паста", к которому меня постоянно склоняли) и увидел код, который отучился писать ещё на порах первоначального изучения языка "C". Речь идёт о таком вот (для примера) наборчике "if () else if ()":
if (hnNotTooShortName == VAL_1)
*ptr = RET_1;
else if (hnNotTooShortName == VAL_2)
*ptr = RET_2;
else if (hnNotTooShortName == VAL_3)
*ptr = RET_3;
else if (hnNotTooShortName == VAL_4 || hnNotTooShortName == VAL_4_1)
*ptr = RET_4;
else
*ptr = RET_DEF;
Должен признаться, я дико не люблю подобные "шедевры". "Ну уж нет", подумал я, "если этот "алгоритм" (вся "соль", конечно, в соответствии констант) нужно реализовать в новом проекте, то по кр. мере, я перепишу код (и за'commit'чу его обратно, в отдельную ветку "untested"), а не буду "натравливать" редактор на поиск и замену всех этих "ptr" и "hnNotTooShortName", на те, которые используется в новом проекте.
Ход моих мыслей по "рефакторингу" был такой:
"... Разумеется, тут лучше switch(). Почему? Да потому, что это позволить сократить кол-во "упоминаний" hnNotTooShortName до одного. Но что делать с "*ptr = RET_xxx"? Ведь после каждого "отдельного" case нужно будет вписать "*ptr = RET_xxx" и поставить "break;" -- снова дублирование (* ptr = ...), да ещё и многословность из-за "break;". И тут я вспомнил про inline:
static inline int calc_value(int const arg)
{ switch (arg)
{ case ARG_1: return (RET_1);
case ARG_2: return (RET_2);
// ...
case ARG_N: return (RET_N);
}
}
sometype somefunc(int another_arg, int *ptr)
{ // some code ...
*ptr = calc_value(another_arg);
// some code ...
}
Да, ещё одна функция, но из-за inline код вряд-ли будет сильно неоптимальнее, чем оригинал. Зато, он стал более инвариантным; такое уже универсальнее, можно и закопи-пастить..."
Как вы думаете, какова была реакция старшего коллеги?
Правильно, неодобрение: "Вместо одной функции несколько!".