LINUX.ORG.RU

Чем плохо много return?

 ,


0

3

В линтерах во многих языках программирования есть такая проверка: https://docs.astral.sh/ruff/rules/too-many-return-statements/

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

В общем случае код выглядит примерно как:

def f(x):
  if cond1(x):
    return res1
  y = process1(x);
  if cond2(y):
    return res2
  if cond3(y):
    return res3
  z = process2(x, y)
  if cond4(x,y,z):
    return res4
  if cond5(x,y,z):
    return res5
  ...  

после убирания return получается что-то вроде

def f(x):
  done = False 
  if cond1(x):
    res = res1
    done = True
  if not done:
    y = process1(x);
  if not done and cond2(y):
    res = res2
    done = True
  if not done and cond3(y):
    res = res3
    done = True
  if not done:
    z = process2(x, y)
  if not done and cond4(x,y,z):
    res = res4
    done = True
  if not done and cond5(x,y,z):
    res = res5
    done = True
  ...
  return res  

Второй вариант действительно легче читается или я неправильно преобразовал первый во второй?

UPD: С учётом наличия elif

def f(x):
  done = False 
  if cond1(x):
    res = res1
    done = True
  if not done:
    y = process1(x);
    if cond2(y):
      res = res2
      done = True
    elif cond3(y):
      res = res3
      done = True
  if not done:
    z = process2(x, y)
    if cond4(x,y,z):
      res = res4
      done = True
    elif cond5(x,y,z):
      res = res5
      done = True
  ...
  return res  

Вот это читается легче, чем первый вариант?

★★★★★

Последнее исправление: monk (всего исправлений: 1)
Ответ на: комментарий от no-such-file

С return у тебя всегда один выход, независимо от их количества. В современных языках это скорее про try/catch.

Чем raise + catch результата отличается от return + сопоставление по результату?

monk ★★★★★
() автор топика

Чем плохо много return?

Плохо лишь в одном случае - если логика алгоритма плохая.
Бывают конечно алгоритмы, когда возращаемое значение формируется в
зависимости от некоего анализа.
В этом случае продолжать выполнените алгоритмв нет смысла.
Можно конечно сделать, чтобы return был один, а можно много их использовать.
Это чисто субъективно и никак не влияет на качество алгоритма.

Как-то так.

anonymous
()
Ответ на: комментарий от anonymous

У меня в коде иногда в алгоритме используются несколько return, а иногда привожу к одному.
Здесь пожалуй нужно учитывать (как бы это сказать) тонус алгоритма.
Но это всё же более субективно.
По идее в функции должен быть один return.
Так проще смотрится код.
Но всё же алгоритмы бывают разные.
Иногда в такого рода алгоритмах логику лучше привести к использованию switch, но это можкт чуть чуть отразиться на эффективности алгоритма.

anonymous
()
Ответ на: комментарий от anonymous

ваще это(есть точка которую можно указать через которую обязательно пройдёт трасса по завершении рутины али это «динамично») мировозренчески важно

а начинается с фундаментальной(и редко ваще кем указанной) дилеммы: организовавать алго

как некоторое дерево решений на каждом  листье которого  (сложносоставное)действие в очевидном(по пути дерева) контексте  
           либо 
как некоторый конвейер  из набора последовательных тест->действие

вот эти два варианта различные (фунда)ментально

первое это собрать достаточно(полный набор) сведений и осуществить реакцию

второе осуществлять последовательность действий на основе «интеракции со средой»

:)

цикломатическая сложность вроде как одинаковая :)

qulinxao3 ★☆
()
Последнее исправление: qulinxao3 (всего исправлений: 2)
Ответ на: комментарий от qulinxao3

Для примера предложенного monk вполне подходит способ предложенный ранее.

Можно для каждого Res-ы в массиве место отвести и указать индекс элемента содержащего результат.
Ведь тем самым лапши if будет заметно меньше и жффективность кода от предложенного способа не пострадает.
Вообще-то не совсем понял. что monk хочет выяснить …

anonymous
()
Ответ на: комментарий от anonymous

все вон lisp-а бои а по факту всем plex (by Douglass T. Ross) https://en.wikipedia.org/wiki/Douglas_T._Ross#:~:text=His later work focused ...

ибо массив это универсальная память на которой можно построить граф любой сложности - и возвращаемся к "https://en.wikipedia.org/wiki/Decision_table"

qulinxao3 ★☆
()
Ответ на: комментарий от anonymous

Редактирование комментариев с ответами запрещено

все вон lisp-а бои а по факту всем plex (by Douglass T. Ross) https://en.wikipedia.org/wiki/Douglas_T._Ross#:~:text=His later work focused ...

ибо массив это универсальная память на которой можно построить граф любой сложности - и возвращаемся к "https://en.wikipedia.org/wiki/Decision_table"

зы. возможность спискоты и не важно S-expr'ы Маккарти али IPL-IV Нобелевского https://en.wikipedia.org/wiki/Herbert_A._Simon али разыменования указателей сяшки (https://wiki.c2.com/?ThreeStarProgrammer И https://esolangs.org/wiki/Three_Star_Programmer ) али неведомая зверушка plex не_широко_известного ныне Росса

вон в Ross, Douglas T. (August 1991). «From Scientific Practice to Epistemological Discovery». In Floyd, Christiane; Zulligho, Heinz; Budde, Reinhard; Keil-Slawik, Reinhard (eds.). Software Development and Reality Construction

красота необходимости и достаточности косвенности трёх разыменнований для полного НЕИМЕНОВАННОГО(имяславием) :

The surprising (perhaps even amazing) consequence of all this is that :

Although        meaning                may be Nothing
and        meaning of meaning          may be Nothing
the     meaning of meaning of meaning  cannot be Nothing!

так что хорошо что Кодд реляционную алгебру на множествах зафорсил в индустрию - иначе бы plex в изводе Бахмана(овского) Программиста-Навигатора по мульти-гипер-графу структур хранения данных всем бы был до сих пор

ну и то что HLL есть то же позволяет ломать копья над важными вопросами ромба-наследования и прочих верлюдов в игольном ушке is-a vs has-a

и сколько return кошерно

qulinxao3 ★☆
()
Ответ на: комментарий от anonymous

plex (который что те же S-exp в этоху статической(аля Фортран без рекурсии )памяти ) излишне универсален

поэтому в массах редко когда реально применяют абстрактное мЫшленье

чаще чисто лингвистические преобразования

и поэтому шок(али видимость ) такой от льльмымок

qulinxao3 ★☆
()
Последнее исправление: qulinxao3 (всего исправлений: 2)
Ответ на: комментарий от anonymous

Очевидно если произвольный граф сводим к дереву а то к дереву с узлами арности не больше двух

ага

ващет граф с вершинами арности не более 3 необходим - это откуда то из NP полноты

так то текст это линия - но необходимы семантические связи для полного феншуя

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

однако дерево (а обычное бинарное если отслеживать не только исходящие но и от родителя входящию - это 3-арность) не достаточно

достаточно DAG

но опять же DAG будет как то эмулировать граф с циклом

а вообще ограничивать арность есть 2 причины - гомогенизация узлов чисто из за практики - али теоритические причины для уменьшения пространства анализа

qulinxao3 ★☆
()
Ответ на: комментарий от no-such-file

Вообще-то, нет. Именно про return’ы. Правило появилось как реакция на доструктурное программирование, когда нормой было прыгнуть на метку в середине функции (обратите внимание на один вход) и выпрыгнуть оттуда с любой строки. А исключений тогда и вовсе не было.

ugoday ★★★★★
()
Ответ на: комментарий от ugoday

Вообще-то, нет. Именно про return’ы

Вообще нет

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

ЛОЛ. В доструктурном программировании не было функций. Были подпрограммы. И было принято прыгать не на метку внутри подпрограммы, а на метку ВНЕ подпрограммы. Именно это и называется несколько точек выхода. Когда у тебя подпрограмма обрабатывающая Ignore/Retry/Abort при каждом выборе делает goto в три разных места. А в структурном программировании это запрещено на уровне языка, return возвращает всегда в одну и то же место – туда где был вызов процедуры/функции.

no-such-file ★★★★★
()
Ответ на: комментарий от monk

Чем raise + catch результата отличается от return

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

no-such-file ★★★★★
()
Ответ на: комментарий от monk

ублажить линтер

Да, из всего набора линтеров процентов 80 отключаются. Потому что они безумные. И оставшиеся иногда дают ложно-положительные срабатывания. Которые так или иначе приходится глушить.

Такова работа с литерами. Причём большая часть из них отключена из коробки. По крайней мере в Гошке так.

А Вы зря сишников спрашиваете. Они же апологеты дрисни. Шутка.

thegoldone ★★
()
Последнее исправление: thegoldone (всего исправлений: 1)
Ответ на: комментарий от qulinxao3

ваще это(есть точка которую можно указать через которую обязательно пройдёт трасса по завершении рутины али это «динамично») мировозренчески важно

Это проще делается так:

def f(x):
  r = inner_f(x)
  # вот точка обязательного прохождения
  return r

def inner_f(x):
  ...
  return res1
  ...
  return res2
  ...
  return resN
  ...
monk ★★★★★
() автор топика
Ответ на: комментарий от no-such-file

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

raise может быть только туда, где была вызвана функция. Единственное отличие от return только в том, что если в точке возврата нет catch, на этот результат будет автоматически вызван raise. Можно не вводить особые правила для try/catch, а использовать обычное значение возврата как в Zig.

Для перехода в любое место нужен goto или вызов продолжения. Но если брать Scheme, то таким внезапным переходом может быть вызов любой функции, переданной в параметре (потому что там продолжение синтаксически является функцией).

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

если в точке возврата нет catch

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

Можно не вводить особые правила для try/catch, а использовать обычное значение возврата как в Zig.

В языке не должно быть объектов. Потому что иначе непонятно как проверять дополнительное значение при инициализации. Кроме этого в языке не должно быть перегрузки операторов. Потому что a+b может внутри зафейлиться, а оператор как-бы не предполагает множественных значений (да и как ты будешь их проверять внутри выражения).

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Потому что иначе непонятно как проверять дополнительное значение при инициализации.

Которое описывает ошибку? Как объект-наследник класса Error.

Кроме этого в языке не должно быть перегрузки операторов.

Потому что a+b может внутри зафейлиться, а оператор как-бы не предполагает множественных значений (да и как ты будешь их проверять внутри выражения).

В Zig перегрузки операторов нет, но ничто не мешало бы её сделать. И работало бы также:

r = try a + b; // если a + b вернуло ошибку, возвращаем ошибку выше

или

if (a + b) |number| {
    doSomethingWithNumber(number);
  } else |err| switch (err) {
    error.Overflow => {
      // handle overflow...
    },
    ...
  }

Да, написать a + b + c не получится, но когда в С++ оператор вызывает исключение, то его вообще практически невозможно поймать в части выражения. А в контексте того, что

auto r = a + b + c;

и

auto r1 = a + b;
auto r = r1 + c;

совершенно разный код (по времени жизни значений), то хорошего решения нет вообще.

monk ★★★★★
() автор топика