В какой момент табу иметь циклы внутри циклов?

23

Просто любопытно. Максимум, что у меня когда-либо было, это цикл for внутри цикла for, потому что после прочтения этого слова Линусом Торвальдсом:

Вкладки состоят из 8 символов, и поэтому отступы также состоят из 8 символов. Есть еретические движения, которые пытаются сделать углубления в 4 (или даже 2!) Символа глубокими, и это похоже на попытку определить значение PI равным 3.

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

Теперь некоторые люди будут утверждать, что наличие 8-символьных отступов делает код слишком далеко вправо и затрудняет его чтение на 80-символьном экране терминала. Ответ на этот вопрос заключается в том, что если вам нужно более 3 уровней отступа, вы все равно облажались и должны исправить свою программу.

https://www.kernel.org/doc/Documentation/CodingStyle

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

Линус шутил?

Это зависит от языка или приложения?

Есть ли какие-то вещи, которые абсолютно нуждаются в трех или более уровнях зацикливания?

Акива
источник
8
Я запутался, почему вы переходите от отступа к уровням зацикливания? У вас есть большая цитата, обсуждающая отступы, и неожиданно из этого следует вопрос о вложенных циклах.
Питер Б
5
Линус, вероятно, не (только) шутит в этом разделе, но учтите, что это только одно руководство по стилю, и то же самое руководство по стилю подчеркивает, что «стиль кодирования ядра является супер простым», то есть в большей степени, чем другие стили.
5
@Akiva Вы не можете пройти через 4-мерную матрицу, не имея 4 вложенных цикла. Я нахожу безумным, что кто-то ограничит количество вложенных циклов, которые вы можете иметь. Линус явно был очень общим, и вы не должны воспринимать все, что читаете, как священное писание.
Alternatex
9
@ Alternatex То, что вам нужно 4 цикла, не означает, что они должны быть лексически вложенными. Из цитаты совершенно очевидно, что мы говорим о том, как организовать код, а не о выполнении.
4
@delnan Я не говорю, что 4 вложенных цикла визуально приятны, и я знаю, что есть и другие способы сделать это, но я нахожу глупым, как ОП воспринял слова Линуса так буквально. 4-й уровень отступа = конец света. Дай мне перерыв.
Alternatex

Ответы:

19

Ядро сильно предпочитает простые алгоритмы

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

Кроме того, ядро ​​Linux отличается от кода большинства приложений в отношении требований к аудируемости и тестированию - и поэтому предпочло бы не иметь вложенный алгоритм уровня 4+ в одной функции. Должно быть очевидно видеть, что каждый фрагмент кода делает точно и подробно, включая все возможные процессы управления и крайние случаи. Глубоко вложенный код препятствует этому.

Петерис
источник
Так вы думаете, что с языками более низкого уровня, такими как C, глубоко вложенные циклы, как правило, более запретные becauseпроекты, использующие языки более низкого уровня, выигрывают от стиля кодирования, который фокусируется на более простых алгоритмах?
Акива
4
@ Akiva Я бы не привязывал это к языкам более низкого уровня или Си как таковым, а скорее к области кода. Я думаю, что аналогичные рекомендации применимы к любому языку при написании кода, который должен быть надежным, сфокусированным на безопасности и проверяемым за счет других вещей. Например, библиотека шифрования, написанная на Java или Haskell, также должна быть написана в стиле, который делает вещи максимально простыми, ограничивает вложение и пытается разделить все на куски, которые можно легко проанализировать со всеми возможными последствиями.
Петерис
Очень проницательный и полезный комментарий / ответ. Просто любопытно; Какой проект, выполненный сегодня, который использует язык низкого уровня, не будет фокусироваться на надежности, аудите и безопасности?
Акива
7
@Akiva, например, код машинного обучения, где вы можете использовать C только из соображений производительности, но не сильно заботитесь о надежности или безопасности, поскольку он будет выполняться внутри в контролируемых условиях. Кроме того, реализация простых бизнес-функций на небольших встроенных микроконтроллерах - на практике это часто имеет дело, например, с акцентом на функции и скорость разработки за счет качества и безопасности, но использует языки низкого уровня.
Петерис
49

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

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

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

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

Гонки легкости с Моникой
источник
6
Я считаю, что «декларация» о том, что вкладки состоят из 8 символов, относится именно к разработке ядра. Эта цитата взята из руководства по кодированию для конкретного проекта и не предназначено для использования в качестве руководства общего пользования, и, таким образом, ожидается, что оно будет достаточно самоуверенным.
Ли Райан
6
@LieRyan: Тогда это все равно - руководство по кодированию для всего, что не имеет никакого дела, диктует, насколько широко я устанавливаю свои вкладки! Но я подозреваю, что Линус знает это.
Легкость гонки с Моникой
6
и, конечно, это зависит от языка - в c # обычно вы делаете отступ внутри своего пространства имен, в своем классе и в своем методе ... вы уже находитесь на 3 уровнях отступа, прежде чем даже говорить о том, что тела операторов потока управления являются отступ.
PeterL
3
@LightnessRacesinOrbit Я интерпретирую комментарий «Вкладки в 8 символов», чтобы не означать, что вы должны лично просматривать вкладки как 8 шириной в вашем редакторе, но для целей других правил в руководстве по стилю (например, «Ограничение на длину строк»). 80 столбцов, и это крайне предпочтительный предел. ") табуляцию нужно рассматривать как 8 столбцов, это также относится к другим правилам, касающимся выравнивания аргументов в вызовах функций. Опять же, я не думаю, что цель этой строки вообще заставляет вас просматривать вкладки, я раньше делал исправления ядра с 4 широкими вкладками и переформатировал код в конце.
Vality
4
@underscore_d: Кажется, я ошибаюсь: Outside of comments, documentation and except in Kconfig, spaces are never used for indentation, and the above example is deliberately broken.- 6 абзацев ниже цитаты в ОП.
slebetman
16

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

TMN
источник
11
В точку. Слишком легко предположить, что Торвальдс - псих. (Он, конечно.) Он может быть слишком жестким на ваш вкус, но он описывает реальную проблему развития, которая вызывает реальные проблемы. Вам не обязательно делать то, что он говорит, но вы должны подумать, почему он это говорит.
Скудный Роджер
7
@ScantRoger На самом деле, эта цитата Торвальдса звучит слишком жестко, только если у вас нет чувства юмора. Как я помню, ранее в том же документе он предлагал распечатать копию руководства по стилю кодирования GNU только для того, чтобы записать их на какой-то церемонии. Вы вряд ли примете это всерьез, не так ли? В этой цитате его основной целью является определение отступа для ядра linux, состоящего из восьми пробелов, не более и не менее, в этом его суть. Последнее предложение только для того, чтобы подчеркнуть этот момент, а не сказать, что вы не должны использовать больше уровней отступа - не подразумевается жесткость.
Мастер
1
@cmaster Спасибо за контекст, отлично! Отвечая на ваш вопрос, я не воспринимаю ничего всерьез. ;)
Скудный Роджер
2
@cmaster, а затем один читает его ответы на запросы GitHub Pull и длину строки сообщений коммита. Он полный ореховый случай.
Gusdor
3
Торжественное сжигание руководящих принципов кодирования GNU может на самом деле не быть необходимым, но оно полностью в порядке в любой момент времени.
dmckee
13

Линус шутил?

Произведение написано в игровой манере, что говорит о том, что автор знаком с тем, как стиль кодирования обсуждается среди серьезных практиков: у всех нас есть свои предпочтения, и мы их отстаиваем бешено, но языком, по крайней мере, частично в щеку. Мы прекрасно понимаем, что многое из этого - вопрос личного вкуса. Он говорит, во многих словах, "Coding style is very personal, and I won't _force_ my views on anybody"- по крайней мере вне кода, который он лично поддерживает. Но последовательность стиля в данном проекте - очень хорошая идея. Я бы предпочел кодировать стиль, который мне не нравится, чем иметь дело с несколькими стилями в данной функции.

Вот пример явно игривого письма:

However, there is one special case, namely functions: they have the
opening brace at the beginning of the next line, thus:

int function(int x)
{
    body of function
}

Heretic people all over the world have claimed that this inconsistency
is ...  well ...  inconsistent, but all right-thinking people know that
(a) K&R are _right_ and (b) K&R are right.  Besides, functions are
special anyway (you can't nest them in C).

Игривый (1).

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

С другой стороны, если кто-то может написать ядро ​​Linux без частого превышения трех уровней отступа, трехуровневое ограничение может быть полезным упражнением на некоторое время в вашем собственном коде, просто чтобы посмотреть, куда оно вас приведет. Знаете, это не похоже на смену пола. Это не пожизненное обязательство.

Если вы столкнетесь с кем-то в Интернете, который думает, что он понимает программирование гораздо лучше, чем Торвальдс (2), вы знаете, какие люди любят громко разговаривать в Интернете.

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

(1) Но обратите внимание, как он ошибочно ставит пробел перед эллипсами, два пробела после них и два пробела после полной остановки. НЕПРАВИЛЬНО, НЕПРАВИЛЬНО, НЕПРАВИЛЬНО. И тогда у него есть наглый нагоняй, чтобы ругать еретиков. Еретик это ты, Торвальдс! ЭТО ТЫ!

(2) Если вы хотите поговорить о « понимании того, как спроектировать систему контроля версий », возможно, есть место для дискуссий.

Заметка: Уважаемый пользователь, который неоднократно вносил одно и то же изменение: форматирование в цитируемом материале сохранено в точности так, как предполагал автор. Это потому, что это из эссе о форматировании текста с фиксированной шириной, написанного в тексте с фиксированной шириной, кем-то, кто придумал много времени для форматирования текста с фиксированной шириной. Форматирование является сознательной и преднамеренной частью замысла автора, и оно имеет отношение к предмету.

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

Эд Планкетт
источник
3
Прекрасный ответ. Один из случаев, который заслуживает +2 ... (Примечание: .в этом комментарии нет неправильных пробелов ;-))
cmaster
2
Вступительный абзац Линуса, который вы указали, очень важен, так что спасибо вам за это! Я думаю, что первое предложение также очень важно для контекста, в частности, preferred coding styleа такжеbut this is what goes for anything that I have to be able to maintain
Крис Хаас
9

У Линуса очень тупой стиль речи и сухое чувство юмора, но он не шутил в этом случае. Есть ситуации, когда алгоритм требует вложения глубже двух уровней, но вы можете сделать это, используя другие средства, чем отступ кода. Руководство по стилю ядра Linux настоятельно предпочитает эти другие методы из-за сложности поддержки глубоко вложенных циклов, и именно это Линус говорит здесь.

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

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

Карл Билефельдт
источник
3

Есть много вопросов, где совет отличается для тех, кто задает вопрос, чем для тех, кто не задает. Если вы спросите «Должен ли я когда-либо иметь циклы, вложенные глубиной более двух уровней», то для вас, человека, задающего этот вопрос, ответ НЕТ. Если вы спросите, то не делайте этого. Если у вас достаточно опыта, который вам не нужно спрашивать, тогда вы знаете, каков правильный ответ в каждом конкретном случае. И не спорьте, если вы не согласны с ответом, потому что ответ не для вас.

gnasher729
источник
1

Казалось бы, это учебный случай, когда хвост виляет собакой.

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

Занимаясь остальной частью ваших пунктов головы:

Я подумал, что это недопустимая практика.

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

Он шутил?

Трудно определить контекст, но смотри мою первоначальную точку выше.

Это зависит от языка или приложения?

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

Есть ли какие-то вещи, которые абсолютно нуждаются в трех или более уровнях зацикливания?

Да, это очень распространено в некоторых алгоритмах перебора. См. Проблему 31 в проекте Эйлера. Это классический пример проблемы, которую можно решить с помощью грубой силы, используя несколько циклов (8, если быть точным).

Робби Ди
источник
1
Похоже, что проблема 31 не требует брутфорса и может быть решена с использованием алгоритма динамического программирования (правка: это означает, что ваша структура кода не самая лучшая, если вы используете алгоритм брутфорса). Кроме того, Линус считает, что если ваш код требует много уровней отступов, это, вероятно, не лучшая структура для кода.
Винсент Савард
2
@VincentSavard Никогда не говорил, что это требует грубой силы. Не согласен с вашей второй точкой - иногда это самый ясный и краткий подход, не говоря уже о наиболее эффективном в некоторых случаях.
Робби Ди
1
С такой проблемой я обычно не делаю отступы. Я думаю, что у меня был один случай с 20 вложенными циклами, абсолютно тривиальный для записи и без отступов, чтобы вы могли видеть, что циклы были почти идентичны.
gnasher729
1
@RobbieDee: Я хочу сказать, что ваш пример проблемы, решаемой многими циклами, заключается в том, что ваш алгоритм не так эффективен, как решение для динамического программирования, для которого не требуется столько уровней отступов. Таким образом, как сказал Линус, ваши уровни отступов могут быть удалены с помощью лучшего решения. Вы также неправильно поняли мой второй пункт, потому что я согласен с тем, что вы сказали. Иногда это лучшее решение. Иногда не часто и не вероятно.
Винсент Савард
1
Цитата Линуса в значительной степени прямо говорит, что если какой-то код требует чего-то вроде грубого решения этой проблемы-31, то вы все равно облажались - это не будет ни быстрым, ни простым, а операции с ядром должны быть быстрыми и простыми. Включение любого алгоритма O (n ^ 4) в ядро ​​является значительным риском для производительности или проблем отказа в обслуживании, поэтому в этом контексте рекомендация просто предупреждает, что это признак кода, который может быть в корне неуместным и востребованным в Linux.
Петерис
0

Линус шутил?

Нет, это официальные рекомендации.

Это зависит от языка или приложения?

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

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

Так почему 3? Субъективное руководство по кодированию сложно реализовать и невозможно применить автоматически. Установка объективного руководства по кодированию на максимальном уровне отступа требует согласования числа: в ядре Linux они выбрали 3.

Это произвольно, и, видимо, им достаточно.

Есть ли какие-то вещи, которые абсолютно нуждаются в трех или более уровнях зацикливания?

С точки зрения алгоритма, возможно, однако, в достаточно выразительных языках вы всегда можете реорганизовать код в более мелкие фрагменты (будь то с функциями или замыканиями).

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

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

Матье М.
источник
2
Хотя это может быть официальным руководством, найти в коде ядра места, в которых это правило не соблюдается.
MikeB
1
@MikeB: все больше причин для автоматического обеспечения соблюдения принципов ...
Матье М.
1
@MatthieuM. Вы уверены, что понимаете разницу между рекомендациями и обязательными требованиями? Как общее «правило» (если хотите, руководство), рекомендации больше похожи на рекомендации и не соблюдаются.
Брендан