Как стать автором
Обновить

Комментарии 59

Для меня второй вариант предпочтительней. Однозначно можно найти место где возвращается результат.
Хм. очевидно, что во втором варианте результат возвращается в самом конце тела функции. А вот что возвращается — еще надо поискать. Поэтому первый варианта таки будет читабельнее.
а мне по душе первый вариант, зачем лезть дальше в функцию, если (например) критичное условие не выполняется и остальное содержимое функции не будет применено к данному её вызову?
абсолютно верно
иногда вначале функции идет проверка на некое условие и возвращается пустое значение.

Зачем должен отрабатывать дальнейший код функции? А если он еще и ресурсоемок?

Второй способ имеет смысл только иногда, для читаемости сложного кода.
имхо не только для читаемости, временная переменная понадобится в случаях, когда возвращаемое значение используется или изменяется дальше в коде функции (как писал ниже Kupyc)
Пользуюсь первым вариантом.
Первый вариант. Когда я вижу return false; я понимаю, что в этой ситуации функция возвращает false. Когда я вижу $result = false; это значит, что переменной результата присваивается значение false. И я должен просмотреть весь оставшийся код, чтобы понять, вернется ли это значение из функции, перекроется ли ниже, или же даже, скажем, будет участвовать в серии логических операций ( $result = $result || $logicStatement ).
1. объект com.sun.java.swing.plaf.gtk.GTKLookAndFeel возвращается сразу же.
if ("gnome".equals(desktop)) {
          // May be set on Linux and Solaris boxs.
          return "com.sun.java.swing.plaf.gtk.GTKLookAndFeel";
        }
        if ((osName.indexOf("Solaris") != -1) ||
           (osName.indexOf("SunOS") != -1)) {
          return "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
        }


2. Объект com.sun.java.swing.plaf.gtk.GTKLookAndFeel может быть перекрыт объектом com.sun.java.swing.plaf.motif.MotifLookAndFeel.
if ("gnome".equals(desktop)) {
          // May be set on Linux and Solaris boxs.
          result = "com.sun.java.swing.plaf.gtk.GTKLookAndFeel";
        }
        if ((osName.indexOf("Solaris") != -1) ||
           (osName.indexOf("SunOS") != -1)) {
          result = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
        }


Имхо, вопрос поставлен не совсем корректно: если возвращаемое значение сложновычисляемое и модифицируемо в ходе подпрограммы, то вариант будет со временной переменной. В простом случае, лично я лучше послушаю Фаулера и применю рефакториинг «встраивание временной переменной». Т.е. дело не в православности методики, а в требовании реалий. Религиозная же сторона дела рассматривалась тут.
Если думать о быстродействии, то первый вариант лучше (например когда systemLAF != null). Сразу ретурн и не надо выполнять дальнейших операций.
Использую retrun, когда нужно. Функция на 20 строк — какой смысл анализировать её (и человеку, читающему код, и интерпретатору), если на первой строке она не проходит проверку? Естественно, тут return и дело с концом. Это в общем. Однако, могут быть и частные случае, когда можно накапливать/модифицировать result и вернуть в конце.

Однако, бывают случае, когда ставят return'ы чересчур много «раздувая» код. Например:

if (a) {
  return a - 10;
} else {
  return false;
}

Предпочтительней в данном случае не писать else, т.к. return (если он будет) будет в if'е, это делает код более наглядным и снижает «раздутость»:

if (a) {
  return a - 10;
}
// остальные вычисления, на которые можно
// не смотреть, если был return выше
return false;
> когда ставят return'ы чересчур много «раздувая» код

Пардон, имел в виду не «return'ов чересчур много», а «вспомогательных конструкций (типа else из примера выше), связанных с return'ами — чересчур много»
именно!
в приведенном примере 1й метод не намного лучше второго, так как из-за else в первом методе повторяется та же вложенность.
если бы елсов не было, то код фукнции уместился бы в 1м-2м уровнях вложенности — а такой код читать удобней.
> в приведенном примере 1й метод не намного лучше второго

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

Я стараюсь писать достаточно маленькие функции, чтобы подобного вопроса не возникало вообще: 1-6 строчек вычисляем результат, последней строчкой возвращаем. Если функция получается длиннее, то что-то, скорее всего, не так.
Когда надо написать длинные if-ы (всякое бывает), обычно, что объявление result, что много return'ов особой погоды не делают.

Когда я использую вариант с result'ом, я обычно объявляю эту переменную как final, чтобы результат присвоить ровно один раз. Очень помогает когда возвращаешься к коду через несколько месяцев. И понятно, что хотел сделать, и испортить сложно.

Очень был удивлён Вашим кодом и кодом Вашего коллеги. Эти кусочки делают разные вещи. У одного из вас точно бага. Рассмотрите случай когда "swing.systemlaf" равно "CustomLAF", а "os.name" равно "Windows". Ваша функция вернёт "CustomLAF", а функция коллеги — "...WindowsLookAndFeel". Правьте код, пока не Вас не поймал QA.
Мне кажется надо судить не по коду, а по ситуации, остальное лишь дело вкуса.

Бывает момент когда возвращают в return функцию которая выводит какое-либо значение, а бывает и сплошные стринги :).
Если боремся за каждый байтик, то важно не повторятся. А если важна работа процессора, то быстрее будет присваивание…

Я конечно не супер-пупер профессионал, но что-то в этом духе…

Просьба не сильно пинать ногами. «Короли тоже бывали ефрейторами»…
> А если важна работа процессора, то быстрее будет присваивание

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

Мое почтение!
я обычно выхожу как можно скорее.
не думаю, что могу обосновать почему. просто мне так больше нравится. не вижу ничего крамольного в другом подходе.
Ортодоксы предпочитают фунции, начинающиеся с return ;-)
Парадигма с одной точкой выхода уже давно устарела.

Кстати, что ваш друг думает насчет выбрасывания исключений? Они ведь тоже создают еще одну точку выхода. Или он фанат Win32 и GetLastError?
Правильный вариант с временной переменной, он обычно всегда рекомендуется, да и код красивее получается. Но все зависит от алгоритма функции. Для некоторых случаев рекурсии иногда более педпочтителен второй вариант.

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

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

Скорее, всего лишь Ваша локальная привычка. Как и тех, кто рекомендует.

> Правильный вариант

Привычный

> честно говоря, уже привык к нему
Всегда рекомендуется?
Фаулер: www.refactoring.com/catalog/replaceNestedConditionalWithGuardClauses.html
Кент Бек, разработчик Eclipse: habrahabr.ru/blogs/complete_code/40841/#comment_993411
Макконнелл, ссылку не дам (он у меня бумажный), рекомендует использовать второй вариант в ряде случаев «если они улучшают читабельность»
Конечно же не всегда.
«Правильный вариант с временной переменной» —
правильный с точки зрения чего? пруф?
Эм… по поводу первого:
приводятся примеры с освобождением ресурсов. уже давно есть такие конструкции как try/finally
quote: I think it is more that we've moved on and found better solutions to the problem. The original paper was written in an age of goto statements. Now we have structure programming, try/finally, destructors and we know the real problem is functions that try to do too much.
Проще говоря, ваше утверждение правильно для таких языков как C. в этом я с вами не спорю.

по поводу второго: я не понял, как это относится к делу.

докозательства не принимаются :) я все еще думаю, что это исключительно дело собственного стиля, по крайней мере для c++ like.
Ну не буду с вами спорить, честно говоря я сам больше склоняюсь к тому, что это сейчас больше относится к стилистике.

Просто в основном я пишу на пыхапэ, а там сами понимаете, любое правило, даже надуманное, навес золота.
НЛО прилетело и опубликовало эту надпись здесь
Смотря кто этот код будет читать и где код будет дальше изпользоватся. Если я один — сделаю как будет удобно мне. Если это написано в компании где существуют правила по написанию кода — буду писать по правилам.

В любом случае, если функция очень сложная, в камментах можно оставить напоминалку себе (и другим) что результат может возвращаться в нескольких местах.
«Свой» код становиться чужим уже через неделю и приходиться вчитываться и даже ругнуться не на кого если что-то непонятно :) Я стараюсь писать сразу «красиво» и понятно, если что комментируя и добавляя FIXME или TODO если мысль не до конца реализована.

По return-ам — пишу как понятнее. Иногда их несколько, особенно на проверках. Иногда он один, когда нужен результат. Бывает что и комбинированный вариант.
Не вижу смысла фиксировать какое-нить правило для return.
Стараюсь комментировать свой код даже если функция интуитивно ясна и понятна в данный момент. Через пол года я тоже ничего помнить не буду :) Сам часто пользуюсь несколькими точками возврата.

«Дело вкуса» может регулироватся обстоятельствами. У меня такого не было, но предпологаю что «правило одного ретурна» (или какое-нибудь другое жесткое правило) может входит в гайдлайны стиля компании/группы/сообщества.
У вас код не эквивалентный, кажется: в первом случае вернется сразу systemLAF, во втором — даже если result = systemLAF, то property OS.name может его перебить. Во-первых, добавьте else к первому if. Во-вторых, писать надо так, чтобы было легко понять. Так что если это проверка предусловий, то лучше явно написать return сразу, а если это логика работы, то лучше иметь как можно меньше точек выхода.
Наилучший вариант — иметь такие короткие функции, чтобы много точек выхода разместить было негде.
Мне кажется, это дело вкуса.
Сам делаю один return, потому как привык, что должна быть одна точка входа и соотв. одна точка выхода.
Ну так мой мозг устроен )
Есть похожый вопрос на счет if'ов: как правильнее?
пример 1:
function test($param) {
    if(is_null($param)) {
        return false;
    }

    // ... code ...
    return $result;
}

пример 2:
function test($param) {
    if(!is_null($param)) {
        // ... code ...
        return $result;
    } else {
        return fasle;
    }
}

ну и учитывая вопрос топика, вырисовывается еще вариант:
function test($param) {
    $result = false;
    if(!is_null($param)) {
        // ... code ...
       $result = true;
    }

    return $result;
}

По моему первый вариант предпочтительнее, потому что я выхожу из функции сразу же по обнаружении что даной функции коректно не выполнится.
А я наоборот предпочитаю второй вариант, первый имхо страдает ненаглядностью, во-втором или/или, два равнозначных блока кода, а в первом получается что мухи отдельно, котлеты отдельно, условие отдельно, код отдельно. В случае простейшей проверки аргументов — это не так страшно, а если логика функции более сложная — например выход происходит если аргумент после обработки будет равен/не равен какому-либо значению — то уже принцип работы функции менее нагляден, придется просмотреть все условия, находящиеся на одном уровне. Во втором случае тоже — но там поможет иерархия вложенности условий.
Иерархия вложености условий как раз меня отталкивает…
Нужно использовать в том колличестве в котором необходимо, без фанатизма и не изобретать велосипед.
Функция (или метод) должна иметь одну точку выхода. В первую очередь это полезно при отладке. А вообще, эта тема уже поднималась вот здесь
Как раз таки в этом топике в комментариях было доказано обратное ;)
При отладке можно повесить точки останова на всех точках выхода из функции и точно знать, где произошел возврат значения.
пост-детектор людей, учившихся программировать на Паскале
А в паскале может быть только один return? А то я что-то его уже и позабыл совсем… как страшный сон :)
наоборот, в паскале вообще нет оператора return, возвращаемым значением функции становится последнее значение либо переменной с тем же именем, что у функции, либо специальной переменной result
Как писали выше, МакКоннелл в «Code Complete» советует смотреть по ситуации: использовать множественные точки выхода из метода следует в том случае, когда это позволит улучшить читаемость. Если метод большой, это наоборот может усугубить ситуацию…
Всем пофиг, вопрос малозначащий и не требует специальных знаний, а потому любой может и хочет высказать своё мнение. ;)
НЛО прилетело и опубликовало эту надпись здесь
Т.е. до этого вы ходили менее пораженным? :) Расслабьтесь, семантически выверенный код в комментарии возможен, но совершенно не обязателен.
НЛО прилетело и опубликовало эту надпись здесь
а чем плоха конструкция типа?
if (var=func()) something;

если не считать того что 0 или '' эквивалентно false для return из func()
приведение типов в конце концов тоже имеет свои плюсы.
НЛО прилетело и опубликовало эту надпись здесь
Я обычно использую возврат в середине функции, если это возврат из-за выполнения/невыполнения какого-нибудь условия, то есть когда результат быстро вычисляется.

Если вычисление может пойти просто по двум разным путям, то стараюсь сохранять результат в переменной, а потом уже в самом конце его возвращать.
Я пишу на С++, так что смотрю на всё немного со своей колокольни, но, думаю, моё мнение актуально и для этого случая.
Когда нужно написать функцию с несколькими точками выхода, я смотрю, есть ли необходимость в различных завершающих действиях. Если есть, то пользуюсь вторым вариантом (дублировать завершающие операции считаю неверным).
Если же функция достаточно проста, и выход не сопровождается какими-либо дополнительными действиями, то делаю по первому — простому — варианту.
В конечном итоге надо смотреть на отсутствие дублирования кода и читаемость, это самый важный аргумент.
Почитайте на досуге: Кент Бек «Шаблоны реализации корпоративных приложений».
«одна точка входа и одна точка выхода» — имхо, самый православный вариант. Основной плюс его — улучшение структурированности кода в телах функций, при дебаге достаточно отслеживать изменения только одной «возвращаемой» переменной, нужен только один брекпойнт, чтобы увидеть состояния всех локальных переменных перед «возвратом результата». Минус — увеличивает вложенность скобок и сползание кода вправо. Для себя я давно уже как выбрал 2-й вариант, желаний пересмотеть это решение не возникало.
НЛО прилетело и опубликовало эту надпись здесь
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.