6.11. О названиях переменных, отступах и т.д.

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

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

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

1. По поводу названий переменных.

Во-первых, полезно привыкнуть в разных программах одно и то же называть одними и теми же именами. Т.е. если вы привыкли, что \(i\), \(j\), \(k\) — это переменные для циклов, \(res\) или \(ans\) — это ответ на задачу, \(cur\), \(t\) — это некое текущее значение, то по возможности так везде и пишите. Это вам поможет, чтобы 1. не думать при написании новой программы, как какую переменную назвать; 2. когда вы глядите на программу, вам будет намного проще вспомнить, что какая переменная обозначает.

Во-вторых, называйте и используйте переменные так, чтобы вам в них не запутаться. Если массивов много, не надо называть их \(a\), \(b\), \(c\), \(d\), \(e\) и \(f\). Не поленитесь и напишите \(cost\), \(color\), \(was\) и т.д. Конечно, придумывать длинные названия тоже не надо, надо почувствовать баланс. Если у вас всего один массив, то напишите \(a\) и не беспокойтесь. Если два, то не нужно придумывать \(IsVertexVisited\) или \(VertexLastVisitedTime\), если хватит просто \(vis\) и \(ltime\). Если у вас огромное множество переменных, то, конечно, никуда от фраз вида

if (Client[i].status=_free)and(not IsPinging(Client[i].sock)) then begin
или
pALLshutDownAnswer=^tALLshutDownAnswer;

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

Если у вас все-таки 4 массива \(a\), \(b\), \(c\), \(d\), и вы очень хорошо помните, что \(n\) — размер массива \(a\), \(m\) — размер \(b\), \(k\) — размер \(c\) и \(l\) — размер \(d\), то пожалуйста, пишите. Только ещё раз подумайте, действительно ли вы так хорошо все помните. А лучше как минимум вместо \(n\), \(m\), \(k\) и \(l\) написать \(na\), \(nb\), \(nc\) и \(nd\) (хотя мне это тоже не очень нравится) (Да, мне тоже. Потому что нечего называть массивы \(a\)\(d\). Назовите массивы по их смыслам — хотя бы \(w\) если это вес, \(name\) если это имя и т.п. — и тогда пишите хотя бы \(nw\), \(nname\) и т.п.. Хотя все равно нечасто бывают массивы разной длины в одной программе. — П.К.)

Ещё полезно завести себе переменную для обмена — такую, которая вряд ли понадобится где-нибудь ещё (я лично всегда пишу \(ex\) и не думаю, какие из переменных \(a\), \(b\), \(c\), \(aa\), \(ii\), \(jj\), \(s\), \(p\), \(q\), \(w\) мне не жалко для строчки \(ex:=a[i]; a[i]:=a[j]; a[j]:=ex;\)А я редко пишу обмен где-нибудь, кроме как внутри процедур сортировки, в этих процедурах не так много переменных, но все равно завожу специальную \(t\) — П.К.) Если в коде много обменов разных типов, то можно и так сделать: вместо var s:array [1..100] of string; написать

var s:array [0..100] of string;
...
s[0]:=s[i]; s[i]:=s[j]; s[j]:=s[0];

Т.е. завести дополнительный элемент в массиве и использовать его для обмена. Это гораздо приятнее, чем заводить 5 новых переменных ради одной-единственной строчки в коде. (Вообще, не жадничайте и не используйте одну и туже переменную в существенно разных целях — если у вас нет проблем с памятью, конечно. Если вам нужна временная переменная в отдельном куске программы, не думайте, какая из переменных \(i\), \(j\) и т.д. у вас не занята тут, а выделите новую переменную. — П.К.)

Также не помешает использовать одни и те же имена для массивов в алгоритмах на графах. В частности, для поисков в глубину и ширину — хранить, были мы в вершине или нет: например, логические массивы \(vis[i]\), \(visited[i]\), \(was[i]\) и т.п. Тут тоже есть проблема — часто нужно больше, чем 2 значения был/не был: например, в поиске в глубину и ориентированном графе или в поиске в ширину, если нам нужно помнить, за сколько шагов мы дошли до вершины и т.п. Тут можно завести массив \(c\) (если он больше нигде не нужен), \(col\) или \(color\) для поиска в глубину, массив \(d\), \(dist\) расстояний для поиска в ширину.

Ещё придумайте себе какое-нибудь имя для бесконечности и тоже пишите его одинаково: \(INF\), \(inf\), \(infinity\).

Ну и ещё немного. Если раньше написать процедуры nod, nok и poisk было нормально, то сейчас так не модно :) Обычно все-таки пишут по-английски, а не транслитом.

Ещё замечание от меня — П.К. Если замечаете, что часто перепутываете, как назвать ту или иную переменную, выберите один вариант и возьмите в привычку всегда его придерживаться. Два примера: первое: как называть массив, например, имён: name или names? Хорошо звучит var names:array... of string: «имена — массив строк». Но потом names[i]:= звучит коряво: «имена \(i\)-ое присвоить». Поэтому я для себя решил, что всегда в таких случаях пишу без конечного \(s\). Ещё пример: как назвать наибольшую координату: \(maxx\) или \(xmax\)? Я так и не решил для себя, а зря. Неприятно бывает, когда написал программу и первый раз компилишь её, обнаружить, что в половине мест написал \(maxx\), а в половине \(xmax\)

2. Про отступы. Стиль, конечно, у каждого свой, но писать без отступов точно не надо. Это крайне затрудняет чтение кода и поиск ошибок. На сколько делать отступ — решать вам. Но имхо лучше делать постоянный, например, всегда 1, всегда 2 и т.д., а табуляция в паскале таким постоянством не отличается. Отступ размера 1, мне кажется, маловат: пусть у нас много вложенных циклов

for i:=1 to n do begin
 for j:=1 to m do begin
  for ... begin
   //тут много строк кода
  end;
  //тут много строк кода
 end;
 //тут много строк кода
end;

Когда begin и end далеко друг от друга, то очень плохо видно, какой end какому begin соответствует. (В принципе, это же иногда верно для отступа 2, но в гораздо меньшей степени. Я обычно делаю отступ 2, и меня вполне устраивает). Имхо, нормальные отступы — 2 или 4. Опять же надо сказать, что размер отступа зависит от языка программирования. (Например если писать на java где-нибудь на работе, когда нельзя переменные называть \(a\), \(b\), \(c\), а нужно писать так, чтобы было понятно, что они обозначают, то на фоне функций типа Database.Fields.NumberOfDocuments.toString отступ на 2 символа вообще незаметен :) )

Опять же непонятно, как и где именно делать отступ. Вот примеры:

for i:=1 to n do
begin
  //чего-нибудь
  //
end;

for i:=1 to n do
  begin
      //чего-нибудь
      //
      end;

for i:=1 to n do
  begin
      //чего-нибудь
end; (но это вроде совсем ужас:) так писать не стоит)
(собственно, предыдущее тоже ужас имхо --- П.К.)

for i:=1 to n do begin
  //чего-нибудь
end; (это как пишу я-О.П. и я-П.К. :) :)

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

3. Кстати, как правильно где-то было сказано, однотипность отступов, имён и т.д., намного важнее чем сами отступы и т.д. Т.е. если вы редактируете чужую программу, и в ней отступы/пробелы сделаны не так, как вам нравится, то лучше оставить так, как там сделано, и свой код писать в соответствии с теми отступами. И, конечно, если вы пишите свою программу, то тоже стоит все делать однотипно.