Недоступный код: ошибка или предупреждение?

Это вопрос дизайна языка:

Как вы думаете, недоступный код (на языках программирования в целом) должен вызывать предупреждение (например, "сообщить о проблеме и все равно скомпилировать") или ошибку ("отказаться от компиляции")?

Лично я чувствую, что это должно быть ошибкой: если программист пишет кусок кода, он всегда должен быть выполнен с намерением запустить его в некотором сценарии. Но, например, компилятор C#, похоже, не согласен с этим и просто выдает предупреждение.

Примечание: я понимаю, что хорошее обнаружение мертвого кода - очень сложная проблема, но это не главное.

Вот несколько примеров фрагментов кода, где некоторые операторы явно недоступны:

return;
foo();

-

throw new Exception();
foo();

-

if (...) {
  return;
} else {
  throw new Exception();
}
foo();

12 ответов

Решение

Вообще говоря, это должно быть ошибкой.

Однако мне приходит в голову одно исключение:

if (false) {
  doStuffThatITemporarilyDisabled();
}

Некоторые разработчики могут жаловаться, если ваш компилятор запрещает компиляцию для такого кода.

Ошибка означает, что компилятор физически не может справиться с вашим кодом.

Предупреждение означает, что компилятор способен работать с вашим кодом, но он считает, что написанное вами в некотором роде неверно.

Мне кажется, это довольно ясно - это должно быть предупреждение.

Кроме того, как насчет случая, когда я решил сократить метод для целей отладки:

public bool ShowMenu()
{
    return true;
    /* The standard implementation goes here */
}

Я знаю, что это неправильно, но компилятор попросил меня также закомментировать, что код будет просто болью.

Очень часто намеренно создавать мертвый код при отладке - компилятор, который предотвращает это, вряд ли будет популярен среди пользователей.

Я думаю, что это должно быть предупреждением.

Вообще говоря, общее правило таково, что "вы должны рассматривать предупреждения как ошибки". Если я непреднамеренно напишу недоступный код, я увижу его в предупреждениях и все равно исправлю.

Однако иногда, как говорит Нил, вы намеренно создаете мертвый код для целей отладки или по любой другой причине. Я бы очень, очень ненавидел это, если бы компилятор не позволил мне это сделать.

Я думаю, что предупреждение уместно. Затем пользователь может решить использовать свой ДРУГОЙ переключатель, который говорит "обрабатывать все предупреждения как ошибки", когда он выполняет сборку Release. Расширение прав и возможностей разработчика всегда лучше, чем навязывание ему вашего случайного выбора.

Если у вас языковая спецификация:

  • Считает мертвый код ошибкой
  • Не поддерживает предварительную обработку на уровне текста в стиле C
  • Отсутствует комментарий в стиле блока, который может быть вложен в комментарии в стиле линии

... тогда это будет действительно отстой. Крайне важно иметь возможность отключать большие блоки кода без необходимости физического их вырезания из файла.

Я бы предпочел (доказуемо) недоступный код для создания предупреждения или уведомления (например, предупреждения, только без негативных коннотаций). Главным образом потому, что это делает автоматическую генерацию кода немного проще.

Мне до сих пор не ясно, почему Java реализует мертвый код как ошибку. Я использую C и Objective-C, которые имеют препроцессоры, поэтому я могу легко использовать директивы препроцессора для включения (или маскировки) функции / метода, например:

// C code
#define ENABLE_FOO //Comment off this to turn off foo(void);
int foo(void)
{
#ifdef ENABLE_FOO
    // Do actual stuff.
    int returnVaue = 2;
    // ...
    return returnValue;
#else
    return 0; // Turned off
#endif
}
// Compiling using clang, enforcing dead code detection:
// clang main.c -Wall -Werror

или, как в Objective-C, с доступным отражением:

// Class
#define MYCLASS_ENABLE_FOO // Comment off to enable -[MyClass foo]
@interface MyClass : NSObject
#ifdef MYCLASS_ENABLE_FOO
- (int)foo;
#endif
@end
// The like is done in implementation.
// Invoking:
int main(int argc, char **argv)
{
    MyClass *object = [[MyClass alloc] init];
    int value = ([object respondsToSelector:@selector(foo)]) ? // Introspection.
                [object foo] : 0;
    printf("Value: %d", value);
    return 0;
}

Хорошая причина для того, чтобы этот код был на этапе разработки: вы хотите временно отключить определенный код, но вы все равно хотите, чтобы этот код проверялся на синтаксис.

например:

int i = 2, j = 3;
int result = 0;

// FIXME: Commented out for now because I have to recheck calculation
if (false) {
  result = i*2+j+3+i*j;
}

System.out.println("Result of difficult calculation = "+result);

Если вы поставите список "результат = i * 2 + j + 3 + i j;" Просто в / comments * / вы уверены, что при удалении или переименовании определенных переменных (например, i) вы не получите ошибку.

Ответ заключается в том, что окончательное решение относительно того, вызывает ли недоступный код ошибку или предупреждение, должно быть оставлено на усмотрение разработчика. Компилятор должен разрешить либо.

В случае производственного кода выпуска баланс одобряет это, будучи ошибкой. Ни одна производственная программа не должна содержать недоступный код.

В случае отладки / тестирования кода баланс предпочитает быть предупреждением. Чрезвычайно удобно иметь возможность отключать части кода для отладки или тестирования.

Вышесказанное относится только к написанному вручную коду. В случае кода, который был сгенерирован автоматическим инструментом, баланс предпочитает, чтобы это было предупреждением или проигнорировано. Генерация кода, который включает недоступные части, не имеет особых неблагоприятных последствий и может быть чрезвычайно трудной для избежания.

Я думаю, что это должно быть предупреждение по той же причине, что и Роалт. Хороший компилятор также должен исключать этот код из компиляции.

По умолчанию это должно быть предупреждение с флагом компилятора, что позволяет рассматривать его как ошибку.Требование, чтобы это было неизменно тем или иным, невнимательно.

Другие вопросы по тегам