Почему управляющие структуры Паскаля кажутся несовместимыми?

Для меня есть смысл в большинстве управляющих структур Паскаля, например:

for ... do {statement};

if (condition) then {statement};

while (condition) do {statement};

где {оператор} - это либо отдельный оператор, либо блок begin ... end. У меня проблема с:

repeat {statement-list} until (expression);

try {statement-list} except {statement-list} end;

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


person 70Mike    schedule 06.01.2011    source источник
comment
Я совершил ошибку, задав здесь два вопроса: почему структуры управления паскаль несовместимы?, А затем в теле текста спрашивая, не лучше ли ?. Теперь, когда есть отличные ответы на оба вопроса, могу ли я отредактировать это и создать еще один вопрос для другого ответа? Как лучше всего решить эту проблему с помощью StackOverflow?   -  person 70Mike    schedule 07.01.2011
comment
у вас полностью отсутствует концепция составного оператора, которая представляет собой ноль или более операторов, окруженных begin..end   -  person Free Consulting    schedule 07.01.2011
comment
@Mike: вы, кажется, спрашиваете об этом из-за программы форматирования кода; возможно, вы хотите расширить этот вопрос (stackoverflow.com/questions/402737/delphi-code-formatter) или задайте новый вопрос о программе форматирования кода, которая хорошо поддерживает новые языковые функции (переменные классов, константы классов, обобщения).   -  person Jeroen Wiert Pluimers    schedule 07.01.2011
comment
@ 70Mike Как указывает Грег Хьюгилл, это то, что Вирт исправил в Modula-2 и во всех последующих языках. Я считаю, что различие между отдельными операторами и составными операторами, перенесенное из Algol, является одним из его самых больших сожалений по поводу Паскаля. Несогласованность одиночного / составного оператора приводит к ошибкам программиста. Простая ясность в Modula-2 - это правильное решение проблемы.   -  person David Heffernan    schedule 07.01.2011
comment
@ 70Mike (продолжение) Продукт моей компании раньше был реализован в Modula-2 с использованием компилятора TopSpeed, который позже стал Clarion. Когда мы портировали на Delphi (по необходимости из-за отсутствия поддержки со стороны TopSpeed), мы ввели стандарты кодирования, которые запрещали использование отдельных операторов. Все наши операторы if / for / while имеют блоки начала / конца. Я убежден, что это было отличное решение, и это правило остается в силе и сегодня.   -  person David Heffernan    schedule 07.01.2011
comment
@David: мы ввели стандарты кодирования, запрещающие использование одного оператора, - прекрасный пример того, чего НЕ должны делать стандарты кодирования. то есть избавить программистов от необходимости думать о том, что они делают ... просто всегда используйте being / end, и все будет в порядке, вместо того, чтобы думать, безопасно / надежно / разумно / ясно делать то, что Я здесь делаю ?. Как и любой стандарт кодирования, который вводит венгерскую нотацию и префиксы локальных переменных для имен переменных, а не простые переменные, должны быть названы четко и осмысленно, а это все, что вам действительно нужно.   -  person Deltics    schedule 10.02.2011
comment
@Jeroen: Непоследовательно == Непоследовательно. Но имхо, всегда одно и то же ‹› непротиворечиво. Следовательно, непоследовательность ‹› не всегда одно и то же, над чем, похоже, и работает Дэвид. Пример: когда мои дети спрашивают разрешения что-то делать, я иногда отвечаю «да», иногда отвечаю «нет»: не каждый раз один и тот же ответ, но правила, которые я применяю, давая какой-либо один ответ, согласованы.   -  person Deltics    schedule 10.02.2011
comment
@Deltics На самом деле ограничения, налагаемые стандартом кодирования, позволяют нам тратить больше времени на размышления о реальной проблеме.   -  person David Heffernan    schedule 10.02.2011
comment
@Deltics, @David: Я согласен с вами обоими. Стандарты необходимы, чтобы вы могли сосредоточить свое внимание на важных аспектах вашего программного обеспечения. Но они не должны вас задушить.   -  person Jeroen Wiert Pluimers    schedule 10.02.2011
comment
@David - дело в том, что многие люди больше беспокоятся о кодировании в соответствии со стандартами, чем о проблемах бизнеса. Стимулирование мышления всегда дает лучшие результаты, чем чрезмерно предписывающие стандарты кодекса.   -  person Deltics    schedule 11.02.2011
comment
@David дополнительный: это может быть пример выхода, но я думаю, что тот же процесс можно увидеть на работе в Монтане. Когда они ввели числовые ограничения скорости, количество аварий увеличилось вдвое (раньше ограничение скорости было безопасным и разумным). Теория: без числовых ограничений люди должны были думать о том, какая безопасная и разумная скорость была бы для их транспортного средства, их способностей и условий. Имея числовые ограничения, они могли просто сосредоточиться на бизнес-задаче (добраться от пункта А до пункта Б) и действовать с максимальной скоростью. Результат: Больше аварий в бизнес-решении, не меньше. :)   -  person Deltics    schedule 11.02.2011
comment
Хм, я понимаю, что мой предыдущий, но-один комментарий может рассматриваться как противоречащий самому себе ... поэтому, чтобы прояснить ... я хотел сказать, что многие люди отключают свой мозг в присутствии защитного одеяла стандарт предписывающего кодирования. Пока код ставит галочки в высокодетализированных полях стандарта, с миром все в порядке. Так что в конечном итоге они меньше думают в целом. По моему опыту, строго предписывающие стандарты в целом менее успешны, чем то, что другие считают более мягкими. ymmv   -  person Deltics    schedule 11.02.2011
comment
@deltics Это просто форматирование кода. Все нормальные команды, даже с одним участником, соглашаются на стандартное форматирование. Это позволяет каждому легко читать код. Готов поспорить, что вы используете стандартное форматирование. Например, я уверен, что весь ваш код имеет одинаковый отступ. Но почему ты такой предписывающий? Почему бы вам не расслабить это защитное одеяло и не использовать разные углубления для каждого метода?   -  person David Heffernan    schedule 11.02.2011
comment
@David - нет, все здравомыслящие разработчики согласны с тем, что отклонение действительного кода из-за того, что он не соответствует произвольному стандарту форматирования, который не добавляет ничего полезного, является пустой тратой всеобщего времени. Это тратит время на проверку из-за необходимости проверять соответствие, это тратит время разработчика на переформатирование действительного кода с действительного в формате X на действительный в формате Y ИЛИ оно тратит время разработчика на постоянную корректировку форматирования во время разработки (отвлечение < / i> из бизнес-задачи).   -  person Deltics    schedule 11.02.2011
comment
@David еще раз: постоянный отступ - это не то же самое, что произвольное обязательное начало / конец. Да, если в одном методе используются разные отступы, то он наверняка будет приведен в порядок, но не по какому-то произвольному номеру отступа Золотого стандарта, просто внутренне согласованному с этим методом. В моем стандарте кода говорится, что используйте последовательные и четкие отступы, в нем не говорится, что отступ в 3 символа, а затем 2 символа для каждого последующего отступа до максимум 8 уровней глубины отступа. Если требуется дополнительный отступ, выполните рефакторинг (и да, я видел такие стандарты).   -  person Deltics    schedule 11.02.2011
comment
@Deltics У вас двойные стандарты, если вы думаете, что отступы отличаются от того, о чем я говорю! Более того, никогда не происходит проверки и отклонения кода из-за нашего правила начала / конца, потому что оно никогда не нарушается. У нас это работает.   -  person David Heffernan    schedule 11.02.2011
comment
@David: Если кто-то забыл начать / закончить отдельное утверждение, вы должны вернуть его на доработку за несоблюдение. И хотя ни отступы, ни ненужные пары начало / конец ничего не делают для правильности кода, они совершенно по-разному влияют на удобочитаемость. Последовательный отступ помогает этому, ненужное начало / конец ухудшает его (100% устранение неоднозначности ‹› улучшенная читаемость).   -  person Deltics    schedule 13.02.2011
comment
@deltics нет, если я заметил это, я просто исправил его на месте. Занимает максимум 20 секунд. В любом случае никогда не бывает.   -  person David Heffernan    schedule 13.02.2011
comment
@David - Либо ты исправляешь это на месте и знаешь, сколько времени это займет, либо этого никогда не происходит ... что это? Я действительно не думаю, что у вас может быть и то, и другое. ;)   -  person Deltics    schedule 14.02.2011
comment
@deltics, если вижу, исправляю. Если я его не увижу, он останется как есть. Это как если / иначе, или вы отрицаете их существование?   -  person David Heffernan    schedule 14.02.2011


Ответы (7)


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

person Loren Pechtel    schedule 07.01.2011

Никлаус Вирт (разработчик Паскаля) исправил эти несоответствия в своем следующем языке, Modula-2. . В Modula-2 составные операторы, такие как IF, не имеют BEGIN и обязательного END:

IF {condition} THEN
    {statement-list}
END;

Другие управляющие структуры, такие как WHILE, аналогичны и согласуются с REPEAT.

person Greg Hewgill    schedule 07.01.2011
comment
Я бы хотел, чтобы он пошел другим путем и потребовал 'begin' для всех блоков с несколькими операторами - это только мое предпочтение. По крайней мере, в Модуле-2 это последовательно. - person 70Mike; 07.01.2011
comment
@ 70Mike: Это связано с теорией синтаксического анализа. Начало требуется только в том случае, если существует неоднозначность относительно того, будет ли следующий узел в синтаксическом дереве одиночным оператором или блоком, как это делается в Паскале. (И в семействе C; за исключением того, что они используют фигурные скобки вместо ключевых слов. Тем не менее, тот же принцип.) begin - это ключевое слово, которое позволяет синтаксическому анализатору ожидать блок. Когда вы запрещаете отдельные операторы, делая все блоком, который должен заканчиваться end, тогда нет необходимости в begin, чтобы сообщить синтаксическому анализатору, что приближается блок. - person Mason Wheeler; 07.01.2011
comment
IIRC предпочтительным оператором цикла в Modula-2 является LOOP..END; WHILE и REPEAT - это просто частные случаи LOOP (с проверкой + EXIT в начале или в конце - person Marco van de Voort; 11.03.2011

Возникает вопрос: не лучше ли?

Ответ таков: это зависит от обстоятельств, поскольку подобные вещи полностью субъективны. Если только вы не являетесь машиной и не думаете так же.

Да, некоторая проблема согласованности была бы удовлетворительной, если бы мы применяли begin / end для ВСЕХ составных операторов, но там, где окружающие языковые элементы уже обеспечивают естественное вложение, это совершенно излишне.

Рассмотрим оператор CASE:

// "Sensible" syntax

  case VALUE of
    1: DoSomething;
    2: begin
         DoSomethingElse;
         DoMore;
       end;
  else
    DoForAllOtherValues;
    DoMore;
  end;

В сравнении с менее разумным, но более последовательным и «логичным»:

  case VALUE of
    1: DoSomething;
    2: begin
         DoSomethingElse;
         DoMore;
       end;
  else
    begin
      DoForAllOtherValues;
      DoMore;
    end;
  end;

Обратите внимание, что последний «конец» - это часть «дела». Без этого не обойтись.

Я почти уверен, что в ранней версии Chrome (которая стала Oxygene, а затем Prism) на самом деле это был необходимый синтаксис для оператора case. Если так, то это уже не так. По-видимому, здравый смысл возобладал.

По моему личному мнению, удовлетворение требований OGoSC (Objective Gods of Syntactic Consistency) вызывает раздражение у, возможно, меньшего, но на самом деле более актуального для вас и меня, SGoHRaC (субъективных богов человеческой читабельности и понимания).

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

Как в этом случае.

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

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

Фактически, эти «более простые», более «последовательные» правила могут фактически усложнить задачу ... еще раз рассмотрим оператор CASE.

Чтобы это составное начало / конец имело смысл, мы должны сделать «case» отдельным оператором, а не частью пары case / end, поэтому ВСЕ из них должны быть допустимым синтаксисом:

  case VALUE of
    1: DoSomething;
    2: DoSomethingElse;


  case VALUE of
    1: DoSomething;
    2: DoSomethingElse;
  else
    DoOther;


  case VALUE of
    1: DoSomething;
    2: begin
         DoSomethingElse;
         DoMore;
       end;
  else
    DoOther;


  case VALUE of
    1: DoSomething;
    2: begin
         DoSomethingElse;
         DoMore;
       end;
  else
  begin
    DoOther;
    DoMoreOther;
  end;


  case VALUE of
    1: DoSomething;
    2: begin
         DoSomethingElse;
         DoMore;
       end;

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

person Deltics    schedule 07.01.2011
comment
Отвечает на вопрос в конце моего поста - не лучше ли ...? а не заголовок вопроса - Почему ...?. Это отличный ответ на следующий вопрос, который я должен был задать отдельно. Моя вина. - person 70Mike; 07.01.2011
comment
Он действительно отвечает на вопрос, почему: они кажутся несовместимыми, потому что они разработаны для легкого чтения человеком, а не для механического анализа машиной. - person Deltics; 07.01.2011
comment
Вы ошибаетесь - собственно язык Паскаль НЕ имеет else части в switch выражении, см. Здесь books.google.com/. Какая бы реализация не добавила, это расширение else сделало это совершенно несовместимым с тем, как else работает в Паскале. Я видел другие реализации, которые добавляли предложение otherwise: с обычными для случая : правилами. - person Nas Banov; 04.02.2011
comment
Nas - я не ошибаюсь, заявляя, что вариант Delphi языка Pascal имеет предложение else в операторе CASE (где-как вы, с другой стороны, ошибочно называете его переключателем;)). Я не вижу смысла обсуждать строго исходную спецификацию языка Pascal, когда именно производная от Delphi имеет отношение к вопросу. И не понимайте, как и почему вы считаете else в значительной степени непоследовательным в CASE - он кажется совершенно совместимым с его использованием в if / else if / else if / else. в противном случае, с другой стороны, несовместим, поскольку используется однозначно в CASE. - person Deltics; 04.02.2011
comment
@Deltics - нужно ли использовать : после else в if? Можете ли вы иметь более одного оператора в else из if, как в case? ;-) Видите ли, сходство между else и else: только внешнее - person Nas Banov; 10.02.2011
comment
@Deltics: См. Здесь общее имя case Паскаля: en.wikipedia.org/wiki/Switch_statement < / а> - person Nas Banov; 10.02.2011
comment
@Nas - см. Здесь, что СООТВЕТСТВУЕТ этому вопросу: D.E.L.P.H.I, или, если быть точным, ObjectPascal. Мы говорим не о теоретической или академической стандартной версии Паскаля, а о конкретном диалекте. Что касается согласованности, это выходит за рамки (или не настолько, в зависимости от вашего p.o.v) сопутствующих символов, связанных с использованием ключевых слов imho. - person Deltics; 10.02.2011

Наверное. Но языковой дизайн, особенно языки с небольшой историей, редко бывает простым или идеальным.

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

Почему switch в C и производных языках представляет собой единый блок, а отдельные случаи - нет?

person Joey    schedule 07.01.2011
comment
Я подозреваю, что есть какое-то отношение к until 'in the repeat ... until структура, действующая как терминатор списка операторов, и' except ', делающее то же самое для try-except. Это имеет смысл, но мне интересно, есть ли лучшая причина для несоответствия более формальной структуре блока начало ... конец. - person 70Mike; 07.01.2011
comment
Что интересно, я никогда не замечал в этом проблемы (в отличие от других примеров, которые я приводил). - person Joey; 07.01.2011
comment
Я это замечаю, потому что планирую утилиту для форматирования исходного кода Delphi. Я пробовал пару, но пока не нашел ни одной, которая могла бы справиться с патологическим стилем кодирования товарища по работе. - person 70Mike; 07.01.2011

Это связано с тем, как работает парсер. Начало / конец, попытка / исключение и повторение / до тех пор, пока все не будут содержать блоки операторов. Код парсера для начального блока (псевдокода) выглядит примерно так:

procedure ReadBlock;
begin
  Match('begin');
  while CurrentToken <> 'end' do
    ReadStatement;
  Match('end');
end;

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

person Mason Wheeler    schedule 07.01.2011

Думаю, вы задаете неправильный вопрос. Я имею в виду, может быть, вы не видите разницы между группой if / while / for и группой повтора / попытки.

Первой группе нужно что-то (условие или аргументы), чтобы НАЧАТЬ что-то. Второе, напротив, подразумевает НАЧАТЬ что-то. Просто прочтите слова: повторите (следующее) и попробуйте (следующее).

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

person someone    schedule 07.01.2011
comment
Я не вижу здесь подразумеваемой разницы. Повторение (следующее) может означать просто повтор одного утверждения, а не списка утверждений. 'while (condition) do ...' похоже на 'repeat ... - person 70Mike; 07.01.2011
comment
Вирт тоже, так как он заменил while и repeat на один LOOP в языке-преемнике modula2. Тем не менее, это пахнет языковым хобби. Детали синтаксиса действительно не имеют большого значения. - person Marco van de Voort; 02.03.2016

Отчасти вы правы - по заявлению repeat <stmts> until <expr>.

Кажется немного обманом, что вам не нужен BEGIN-END для согласованности составного оператора, но это сделано для того, чтобы избежать ненужных страданий. Поскольку во всех других случаях вы видите, что вам нужен эффект брекетинга начала-конца, чтобы показать, к какой части кода применяются then, else или циклы do. REPEAT-UNTIL - единственный оператор Паскаля, о котором я могу думать, который требует далеко удаленной второй части - потому что имеет смысл, чтобы условие выхода из цикла было текстовым, где оно будет проверяться - после тела цикла . Альтернативная форма могла быть

UNTIL <condition> DO <statement>

UNTIL <condition> DO
  BEGIN
    <statements>
  END

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

Что касается try <stmts> except <stmts> end - это не из оригинального дизайна и спецификации языка Pascal, это было задумано каким-то разработчиком (Borland? FreePascal?), Поэтому неудивительно, что это непоследовательно - мысль была больше строки «могу ли я сделать это, не нарушая существующие программы», чем общий дизайн спецификации. Другой пример расширения языка был приведен в ответе выше - предложение по умолчанию else в переключателе case - и хотя я нахожу это очень полезным и использовал его еще во времена Turbo Pascal, это ужасно несовместимо с использованием else в if конструкция. Таким образом, я нашел другую реализацию, которую я видел и использовал лучше - otherwise:, за которой следует один оператор, как в каждом случае <value>:.

person Nas Banov    schedule 04.02.2011