Подтвердить что ты не робот

Должны ли вы всегда писать код для других случаев, которые "никогда не могут произойти"?

Возьмите некоторый код, например

if (person.IsMale()) {
    doGuyStuff();
} else {
    doGirlStuff();
}

Должно ли это быть записано, чтобы явно проверить, есть ли person.isFemale(), а затем добавить новое, которое выдает исключение? Возможно, вы проверяете значения в перечислении или что-то в этом роде. Вы думаете, что никто не добавит новые элементы в перечисление, но кто знает? "Никогда не бывает", звучит как знаменитые последние слова.

4b9b3361

Ответ 1

Я думаю, вы ответили на свой вопрос. Если вы знаете, вы никогда не увидите дополнительные значения:

bool isSet = ...
if (isSet)
{
    return foo;
}
return bar;

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

Ответ 2

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

Ответ 3

Если вы внимательно прочитаете некоторые из формальных книг, они предлагают, чтобы вы делали такие вещи.

  • Определите пост-условие

    isMale && doGuyStuff || isFemale && doGirlStuff.
    
  • Выведите некоторые утверждения кандидата, которые приведут к этому постусловию

    if isMale: doGuyStuff
    

    Это доказуемо приводит к некоторому постусловию

    if isFemale: doGirlStuff
    

    Это доказуемо приводит к некоторому постусловию

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

  • Вы завершаете следующее:

    if isMale: doGuyStuff
    elif isFemale: doGirlStuff
    

    Обратите внимание, что для предложения else нет правильного использования. Вы никогда не будете - в формальном деривации - получите предложение else. У вас всегда будут условия, которые являются положительными утверждениями: a && b || c && d виды вещей. Редко это будет a && b || !a && c, но даже тогда вы обычно заканчиваете явным условием !a.

Формально, условие "невозможное else" должно быть ограничено выполнением следующих действий.

    if isMale: doGuyStuff
    elif isFemale: doGirlStuff
    else:
        raise HorrifyingSituationError

Если вы когда-либо поднимаете HorrifyingSituationError, это означает, что вы сделали математику неправильно и неправильно вывели утверждения из условий. Или вы неправильно определили пост-условие в первую очередь.

В любом случае, программа была разработана неправильно глубоким и абсолютным способом. Как правило, это не удивительно. Обычно это происходит не сразу, когда вы пытаетесь его протестировать. Если (как это часто бывает), вы выбрали тестовые данные, которые отражают ошибки в исходном определении пост-состояния. Даже тогда, как только вы столкнетесь с этим исключением, вы можете легко отследить его и исправить его навсегда.

Ответ 4

Если НЕ МОЖЕТ произойти в процессе производства (но может произойти во время разработки), я использую assert:

Если он не работает НЕ ДОЛЖЕН, но возможно, я либо вернул ошибку, либо выдал исключение.. p >

Кстати, здесь аккуратный маленький трюк С++, который я где-то подхватил; поскольку многие макросы ASSERT отображают свое выражение в окне сообщения, если утверждение неверно, вы можете использовать следующую форму для ветвей, которые никогда не должны выполняться:

if (person.IsMale())
{
    AdmitEntranceToManCave();
}
else
{
    ASSERT(!"A female has gotten past our defenses. EVERYBODY PANIC!");
}

Строковый литерал оценивает (не-NULL) адрес, который является логически ИСТИНА. Таким образом, использование логического оператора NOT делает его FALSE.

Ответ 5

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

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

Ответ 6

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

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

Ответ 7

@Michael Petrotta - ваш фрагмент кода неверен, поскольку действие DoY() выполняется без учета значения истины условия.

(извините, не оставлять комментарии еще...)

Ответ 8

Помните, что перечисления в С# могут вас укусить:

enum SwitchPosition 
{
    Off = 0,
    On = 1
}

void SetLightStatus(SwitchPosition pos)
{
    switch (pos)
    {
        case On: 
            TurnLightOn(); 
            break;
        case Off: 
            TurnLightOff(); 
            break;
        default:
            // Fugedaboudit -- will never happen, right?
    }
}

Неправильно! Вызов SetLightPosition(2); является законным и будет проходить через случаи в этом операторе switch. Лучше всего бросить HorrifyingSituationError, как предложил С. Лотт.

Ответ 9

Если вы хотите указать блок кода, который "не может произойти", используйте

assert (false);

Ответ 10

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

Ответ 11

Лично я написал строку else как:

} else /*if (person.IsFemale())*/ {

Это оборачивается необходимостью выполнения функции (я не хочу тратить время на ее выполнение, если ее результаты не нужны), но оставляет важную документацию для будущих разработчиков. Теперь ясно, что эта ветвь условного случая охватывает случай IsFemale (в частности), а не случай !IsMale (в общем случае). Вы в основном делаете свои предположения "вслух", что делает менее вероятным, что будущие изменения неправильно поймут, что вы делаете, и сломаете свой код.

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

Ответ 12

Вопрос зависит от вашего контекста - кто-нибудь еще сможет расширить ваш объект Person? Когда андроиды становятся законными людьми, вы можете обнаружить, что оба isMale() и isFemale() могут быть ложными.

Это особенно актуально, если код, который вы пишете, является модулем, который будет использоваться людьми вне вашей группы. Конечно, в этом случае вы могли бы пойти еще дальше, пропустить жестко закодированные тесты и вызвать doGenderStuff() для объекта, созданного соответствующим factory...

Ответ 13

Так как есть так много ответов, я просто покажу вам, что переусердство выглядит так: (на С++)

if(!DoOperation())
{
    // Allocate for a message
    char * pMsg = new char[256];
    // Make sure the memory was allocated
    if(!pMsg)
    {
        cout << PREDEFINED_OUT_OF_MEMORY_MESSAGE << endl;
        exit(0);
    }

    if(!strcpy(pMsg,"Operation failed!"))
    {
        cout << PREDEFINED_STRCPY_FAILED_MESSAGE << endl;
        exit(0);
    }

    // Now let the user know there was an error
    ErrorDetailStructure * pError = new ErrorDetailStructure();
    if(!pError)
    {
        cout << PREDEFINED_OUT_OF_MEMORY_MESSAGE << endl;
        exit(0);
    }

    // Copy the message to the error structure
    if(!strcpy(pError->pMessage,pMsg))
    {
        cout << PREDEFINED_STRCPY_FAILED_MESSAGE << endl;
        exit(0);
    }

    // Alert the user - yes, ErrorDetailsStructure
    // overloads operator<<
    cout << pError;

    delete pError;  // the destructor frees pMessage member

    // Now we need to log this error
    some_file_pointer * pFile = OpenAFilePointer("/root/logfile");

    if(!some_file_pointer)
    {
        cout << PREDEFINED_OPEN_FILE_ERROR_MESSAGE << endl;
        exit(0);
    }

    some_file_pointer->WriteError("Something went wrong. Guess what it was.");

    // Don't forget to free some_file_pointer
    delete some_file_pointer;

    exit(0);  // Just quit. Give up.
}

В итоге мне стало очень весело. С этим связано очень много проблем (и дизайн настолько плох), что я получил хороший отклик, написав его.

Ответ 14

Я бы сохранил код как можно более чистым и коротким, а затем добавил утверждения в места, которые не загрязняют чистоту:)

if(male)
{
  ...
}
else
{
  ...
}

// other stuff that nobody cares about...
assert(male||female);