Как сделать код более читабельным с оптимизацией компилятора на месте? - PullRequest
1 голос
/ 22 марта 2012

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

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

// yeild sunRays when sky is blue.
// yeild sunRays when sky is not blue and sun is not present.
if (yieldWhenSkyIsBlue)
{
    // if sky is blue and sun is present -> yeild sunRaysObjB.
    if (sunObjA != null)
    {
        yield return sunRaysObjB;
    }
    else
    { 
       // do not yield ; 
    }    
}
else
{
    // if sky is not blue and sun is not present -> yeild sunRaysObjB.
    if (sunObjA == null)
    {
        yield return sunRaysObjB;
    }
}

В отличие от чего-то подобного:

// yeild sunRays when (sky is blue) or (sun is not present and sky is blue).
// (this interpretation is a bit misleading as compared to first one?)
if(( sunObjA == null && yieldWhenSkyIsBlue ==false) || (yieldWhenSkyIsBlue && sunObjA != null) )
{
    yield return sunRaysObjB;
}

Чтение первой версии показывает вариант использования лучше для будущих улучшений \ обновлений? Вторая версия кода короче, но чтение ее не делает сценарий использования очевидным или нет? Есть ли другие преимущества второго случая помимо краткого кода?

update # 1 : да, он возвращает ObjB в обоих случаях, но в зависимости от условия он может вообще не дать. поэтому стратегия решает, когда уступить, а когда нет. (еще одна причина, почему читабельность является бесценной)

update # 2 : обновлен для лучшего примера сайта. скопировал синтаксис из stripplingWarrior

update # 3 : обновлено: «Что вы ожидаете, когда солнце выйдет, а небо голубое».

Ответы [ 5 ]

7 голосов
/ 22 марта 2012

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

Большинство программистов сочтут этот логический поток очевидным и естественным: вы вернете ObjB, если ObjANULL, или если он не NULL и howtoYieldFalg установлено.

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

Обновление

Еще раз взгляните на примеры кода: они не являются логически эквивалентными.Что вы ожидаете, когда солнце выйдет и небо голубое?Второй пример кода правильно позволяет солнечным лучам сиять в этом случае, тогда как первый пример - нет.

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

Обновление 2

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

    /* Explanation: We live on a strange planet where the sun's
     * rays can shine if the sky is blue while the sun is out,
     * or if the sky is not blue and there is no sun. */
    bool sunIsPresent = sunObjA != null;
    if ((skyIsBlue && sunIsPresent) ||
        (!skyIsBlue && !sunIsPresent))
    {
        yield return sunRaysObjB;
    }
3 голосов
/ 22 марта 2012

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

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

first example

и

second example

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

Фактическидальнейшее отслеживание возможных маршрутов приводит к тому, что первый пример имеет возможные маршруты длиной 6,8,8,6 инструкции, в то время как второй пример имеет маршруты 8,10,10 соответственно.В обоих случаях средняя длина прогона составляет 7 инструкций, но мы видим, что в первом случае лучшая длина прогона лучше.Без дополнительной информации компилятор не может сказать, что лучше.

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

2 голосов
/ 22 марта 2012

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

2 голосов
/ 22 марта 2012

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

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

1 голос
/ 22 марта 2012

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

Учитывая это, идиоматический код легче читать, даже если он менее лаконичен.Опытные читатели языка распознают общий шаблон быстрее, чем незнакомый код, который, возможно, «более человечный», но нарушает привычный шаблон.Циклические / инкрементные конструкции являются хорошим примером кода, который не должен удивлять.Итак, мой подход таков: будь выразительным, но не слишком умным.

...