?

Log in

No account? Create an account
глупый программистский вопрос - Поклонник деепричастий [entries|archive|friends|userinfo]
Anatoly Vorobey

[ website | Website ]
[ userinfo | livejournal userinfo ]
[ archive | journal archive ]

Links
[Links:| English-language weblog ]

глупый программистский вопрос [апр. 12, 2003|03:04 pm]
Anatoly Vorobey
(только программистам интересно, наверное)

Почему в процедуральных языках, как правило, нет оператора досрочного выхода из блока? Как break в C, но чтобы работал не только из циклов, а также внутри if-then или вообще любого блока.

Постоянно приходится делать глупые вложенные цепочки условий или некрасивые трюки типа while(1) и выполза по break'у (ну или, понятно, их аналоги в других языках).

Есть какая-то глубокая причина этому?
СсылкаОтветить

Comments:
[User Picture]From: sergeax
2003-04-12 05:20 am
Видимо, десятилетиями вбиваемая неприязнь к оператору GOTO :) Хотя с точки зрения машинной трансляции короткий GOTO (в пределах одной страницы процессорного кэша) абсолютно идентичен вложенным условиям.

Кстати, в VBScript (и VB.NET) есть операторы выхода из цикла Exit For и Exit Do, а также сложные ветвления типа If ... ElseIf ... ElseIf ... Else

А вообще какие-нибудь профессора скажут наверняка, что подобную функциональность надо выносить в функции, из которых можно выскочить по return(что-то). Иначе в начале блока, следующего за тем, из которого можно выпрыгнуть, придется проверять, как именно мы из этого предыдущего блока вышли и что можно предполагать относительно измененных внутри него переменных.
(Ответить) (Thread)
From: sply
2003-04-12 06:35 am
Профессора скажут, что провильн обудет если из функции только один return, в конце. А до этого трахайтесь как хотите. И предложат использовать язык с exceptions
(Ответить) (Parent) (Thread) (Развернуть)
(Удалённый комментарий)
[User Picture]From: avva
2003-04-12 07:52 am
Проблема в том, что неясно (как я объяснил в ответе lvalien ниже), в чём такое особое отличия выхода из цикла от выхода из блока. Про оба можно сказать, что они соблюдают и нарушают принципы структурного программирования в одинаковой или почти одинаковой мере.
(Ответить) (Parent) (Thread)
From: oblomov_jerusal
2003-04-12 05:41 am

А почему в C break может выйти только из самого внутреннего цикла? Почему нельзя написать что-то вроде main_loop: for(...) { .... if (foo) break main_loop;...} Вроде в каком-то языке (Ада?) я что-то подобное видел.

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


typedef struct _s_nametable_ {
   int count; 
   struct _s_nametable_ *next_nametable;
   struct {
      int value;
      char *name;
   } names[];
} nametable_t;
nametable_t *nametable = malloc(sizeof nametable_t(100));
nametable->names[i].name = "bar";
где для namеtable выделяется место для заголовка и массива names из 100 элементов
(Ответить) (Thread)
[User Picture]From: avva
2003-04-12 07:24 am

Re:

В Джаве есть такой выход из вложенных циклов.

В C, по-моему, нет cleanup'а по двум причинам, в чём-то друг от друга зависящим: во-первых, железо начала 70-х (речь идёт не о мейнфреймах, конечно) его плохо поддерживало; во-вторых, C изначально был задуман как язык, в котором все переходы контроля абсолютно прозрачны для программиста. В C никогда ничего не происходит "за кулисами" с точки зрения выполнения каких-то команд. Именно поэтому сторонники других языков любят называть C макроассемблером, но, с другой стороны, это идеально подходит для системного кода, для realtime-кода, и вообще во всех случаях, когда программист должен более или менее чётко представлять, что происходит во время исполнения вот этой конкретной строки кода.

Структура динамического размера - да, было бы удобно, хотя это syntactic sugar, по сути дела.
(Ответить) (Parent) (Thread) (Развернуть)
[User Picture]From: igorbor
2003-04-12 06:15 am
Строго говоря, механизм для выхода из любого блока существует, называется - GOTO ^)

Я думаю, что это тяжелое наследие Паскаля, в котором, как мне помнится, нет выхода из цикла по BREAK.
(Ответить) (Thread)
From: ex_jetteim
2003-04-12 07:29 am
Borland его сделали в Delphi Language.
В Oberon тоже есть.
В GNU Pascal тоже есть.
Нету только в виртовском.
(Ответить) (Parent) (Thread) (Развернуть)
[User Picture]From: smilga
2003-04-12 06:17 am
Можно писать так, чтобы блок всегда был последним в функции. У Стили была примерно на эту тему статья [PDF, 1.9M] под названием “Lambda, the Ultimate GOTO”.
(Ответить) (Thread)
(Удалённый комментарий)
(Удалённый комментарий)
From: (Anonymous)
2003-04-12 06:24 am
В Java, кажется, можно выйти по break из любого блока (и не только блока), обозначенного меткой.

http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#6842

(Ответить) (Thread)
From: (Anonymous)
2003-04-12 06:28 am
под "и не только блока" я имел в виду, что-то типа:

label:
if(condition)
{
...
if(another) break label;
...
}

Не в чем проверить, работает это или нет.
(Ответить) (Parent) (Thread)
[User Picture]From: lvalien
2003-04-12 06:29 am
"Почему в процедуральных языках, как правило, нет оператора досрочного выхода из блока?"
Это "скрытый" оператор перехода. В некоторых из тех языков, в которых он есть (и даже есть полноценный оператор перехода), эти идеологические уступки стараются не афишировать :)
Если память мне не изменяет, то в фирменном учебнике по борландовскому паскалю примеры с операторами перехода отсутствовали (что не мешало существовать им самим в борландовской версии паскаля - или путаю?).
(Ответить) (Thread)
[User Picture]From: avva
2003-04-12 07:30 am
Проблема в том, что я не понимаю принципиальной разницы между оператором досрочного выхода из цикла и оператором досрочного выхода из блока. Тем более что второй симулируется с помощью первого и конструкции типа while(1), что на практике повсеместно и происходит.

Оба можно назвать "скрытыми операторами перехода" в одинаковой мере. Если есть первый, почему бы "за ту же цену" не предоставить второй?
(Ответить) (Parent) (Thread)
From: sply
2003-04-12 06:37 am
Наследие академического подхода. В новых языках есть exceptions.
(Ответить) (Thread)
From: (Anonymous)
2003-04-12 08:47 am
В PHP есть break, который хоть и не работает с if {}, может принимать аргумент, указывающий сколько вложенных структур надо покинуть. Если верить документации, работает с for, foreach, while, do while и даже switch :)))
Правда я не знаю, сколько "правильных" программистов позволяют себе им пользоваться вне switch, а тем более с дополнительным аргументом :)
(Ответить) (Thread)
[User Picture]From: 37
2003-04-12 08:55 am
Никогда не воспринимал это как проблему. Зависит от сложившегося стиля. Причина неиспользования break label и continue label чисто историческая и исправлена в новых языках, таких как Java или C#. Справеливости ради, если мне память не изменяет, существовала уже вместе с exceptions в IBM-овском PL/X накануне его безвременной кончины (break & loop с меткой, кажетсяи в rexx). Но таких мелких неудобств всегда довольно много. Вот, например, терпеть не могу, что декларация for(int i = 0;... в C++ носит открытый характер (действует и после завершения блока). Или это исправлено в последней версии стандарта? Оператор goto реализован во многих языках, но причина его неиспользования довольно очевидна. Кроме этой очевидной причины есть еще менее очевидные, вроде автоматической верификации программ, идея, с которой Дейкстра (и, кажется, наш Ершов) носился еще 25 лет назад, но примитивные элементы реализации которой я начал замечать только сейчас.
(Ответить) (Thread)
[User Picture]From: tejblum
2003-04-12 11:59 am
терпеть не могу, что декларация for(int i = 0;... в C++ носит открытый характер (действует и после завершения блока). Или это исправлено в последней версии стандарта?

Да, в стандарте это давно исправлено (стандарт был только один, в 1998 году кажется; драфты с этим исправлением появились еще раньше). Удивительно, что в MSVC это не только осталось "по старому", но даже и переключателя не появилось для "нового" поведения (во всяком случае так было до самого последнего времени) -- очень неудобно многоплатформенные программы писать.
(Ответить) (Parent) (Thread) (Развернуть)
[User Picture]From: gera
2003-04-12 08:55 am
Сразу приходит в голову return как выход сразу из всей функции, вне зависимости от того, насколько глубоко ты там сидишь в циклах и сравнениях.
(Ответить) (Thread)
[User Picture]From: avva
2003-04-12 08:59 am

Re:

Да, конечно. Но всего лишь из-за того, что тебе нужно сделать серию сравнений, не всегда есть смысл выделять её в отдельную функцию.

Ситуация: тебе нужно сделать одну проверку; если она проходит, вторую; если эта проходит, третью, и если третья проходит, выполнить некую нетривиальную последовательность действий. Возможность проведения каждой провеки зависит от успеха предыдущей. Проверки относительно сложны, так что их не записать в качестве одного длинного if'а. Логика происходящего абсолютно прозрачна. Но тебе приходится делать три вложенных блока, или трюк с while(1), или выделять это всё в отдельную функцию, что вовсе необязательно имеет смысл делать.
(Ответить) (Parent) (Thread) (Развернуть)
From: pavelgr
2003-04-12 10:48 am
exceptions?

polagaju 4to tak slo*ilos' isklju4itel'no istori4eski... nu i pljus kone4no opredelennaja stepen' leni razrabot4ikov C.
(Ответить) (Thread)
[User Picture]From: oxfv
2003-04-12 11:34 am
Без break и continue для циклов не обойтись, они важны. И они должны работать как сейчас даже внутри всяческих внутрицикляных кондиций. То есть использовать те же слова для выхода из блока нельзя. Я думаю, товарищи изобретатели языка пренебрегли удобством наличия блокового брейка в пользу краткости словаря языка. Да, неудобство, но мало ли что неудобно. Все же без этого жить можно.
(Ответить) (Thread)
[User Picture]From: anton
2003-04-12 12:35 pm
А нужен ли такой оператор, если его легко можно эмулировать имеющимися средствами языка(скажем, inline-функцией), и он не улучшит структуру, т.к. в большинстве случаев эти некрасивые решения, о которых вы говорите – результат плохой продуманности кода, а совсем не реальная необходимость.
(Ответить) (Thread)
[User Picture]From: auto194419
2003-04-12 03:18 pm

в ADA есть:

exit [loop_name] [when condition];

в REXX тоже есть:

leave [var_name];

Так что в нормальных языках всё есть :)
(Ответить) (Thread)
[User Picture]From: avva
2003-04-12 03:27 pm

Re:

Ну-ну :)
(Ответить) (Parent) (Thread)
From: ex_nikitagr
2003-04-12 05:38 pm
извините, но только они называются "процедурные языки"
(Ответить) (Thread)
[User Picture]From: 109
2003-04-12 08:51 pm

как нету?

любой блок, из которого в середине надо выйти, можно обрамить в try-except, и когда надо выйти, сделать raise/throw. это и с идеологической точки зрения будет правильно.
(Ответить) (Thread)
(Удалённый комментарий)
From: (Anonymous)
2003-04-13 05:13 pm
#define block(label) if (0) label:; else
#define leave goto


...
block( foo ) {
...
leave foo;
}

))
(Ответить) (Thread)
[User Picture]From: avva
2003-04-14 03:37 am

Re:

Ужас :)
(Ответить) (Parent) (Thread) (Развернуть)
a paaachemu? - (Анонимно) Развернуть