-
Сабж...
Первый раз в жизни вместо написания лишних строк решил применить метку.
Теперь меня интересует насколько это нехорошо?
Как вы относитесь к использованию меток, например в таком коде:
...
bitmove:=1;
while field<>0 do
begin
if (bitmove and field) = bitmove then
begin
field:=field xor bitmove;
for z:=0 to workseccount-1 do if secarr[z].field=bitmove then goto lbskip;
secarr[workseccount].field:=bitmove;
secarr[WorksecCount].mt:=mt;
inc(workseccount);
lbskip: end;
bitmove:=bitmove shl 1;
end;
...
?
-
Сразу бросается в глаза неправильная разложение на функции. В одной функции 2 условных оператора и 2 цикл и так понимаю ещё под многоточием много неправильного кода.
Внутренний цикл надо вынести в отдельную функцию и обозвать что-то типа Pos или Search.
Зачем это нужно? Вот вы скажете для красоты. Кто-то скажет что такой код становиться само документированным и его проще читать. Но я скажу следующее. Элементарные функции проще проверить. Причем такую проверку можно поручить и автоматическим тестам.
-
Хоть где - нейтрально, лишь бы не говнокод был.
-
> вместо написания лишних строки много сэкономлено?
> в таком коде: ...плохо.
func/proc
...
function lbskip:Boolean; begin for z := 0 to workseccount-1 do if (secarr[z].field = bitmove) then Exit(True); Exit(False); end;
...
begin
...
if (not lbskip) then begin
secarr[workseccount].field := bitmove;
secarr[WorksecCount].mt := mt;
inc(workseccount);
end;
...
end;
-
Метки воплне допустимы там, где это помогает упростить код.
-
> NoUser © (20.05.16 19:43) [3]
Ну это мне нравится, но:
> Exit(True); Exit(False);
Delphi 7 такого не знает
> Pavia © (20.05.16 18:46) [1]
>
> Сразу бросается в глаза неправильная разложение на функции.
> В одной функции 2 условных оператора и 2 цикл и так понимаю
> ещё под многоточием много неправильного кода.
Вы предлагаете каждый цикл или условный оператор выносить в отдельную функцию? Да тогда в функциях запутаешься... Я конечно выношу иногда код в отдельные функции, если в одной он уж слишком вложенный и навороченный получается, но когда код функцию можно полностью видеть на экране без использования скроллинга и когда без напряжения видно какой end какому begin'у соответствует (в данном случае функция у меня в 40 строк с 3 вложенными циклами и 6 условными операторами), то такую функцию, я считаю, разбивать на части обычно не стОит.
-
> NoUser © (20.05.16 19:43) [3]
>
> > вместо написания лишних строк
> и много сэкономлено?
1 переменная, с предварительной инициализацией, begin, end и 1 условный оператор.
-
> Вы предлагаете каждый цикл или условный оператор выносить
> в отдельную функцию?
В абсолют возводят только юноши. Жизнь она не только черная или белая она имеет оттенки серого.
Но, грубо говоря да каждый в своя функцию.
Если идут 2-3 последовательных цикла, то разбиваю на функции/процедуры.
Пробовал разбивать и вложенные циклы, чёрти-что получается. Поэтому сейчас допускаю, но не более 2-х.
> (в данном случае функция у меня в 40 строк с 3 вложенными
> циклами и 6 условными операторами), то такую функцию, я
> считаю, разбивать на части обычно не стОит.
У меня средняя длина функции 15 строк. От function до end включая пустые строки.
Гораздо проще разбить подозрительную функцию на кучу простых и забыть о отладчике. Гораздо быстрее набить 5-10 функций. Чем отладить одну большую. С моей скоростью (250 ударов/мин) я эти функции наберу за 5-10 минут, против полчаса-час потраченного в пошаговой отладке.
При таком подходи, надобность в метках отпадает сама-собой.
> Да тогда в функциях запутаешься...
Ни чуть. Правильные названия позволяет не заглядывать во внутрь функций.
-
> Гораздо быстрее набить 5-10 функций.
Каждый вызов функции затратен.
-
> Pavia © (20.05.16 22:14) [7]
Если функция нужна только в одном месте - я не разбиваю. Смысла не вижу.
Если в нескольких, то чрезмерное разбиение + желание потом немного изменить одну из функций может привести к проблемам. А в теории, так как вы говорите - самодокументирование и простота отладки.
Соглашусь с [2]
-
> SergP © (20.05.16 18:25)
негативно. так как в наше время метки встречаются крайне редко, мозг хуже воспринимает данную конструкцию, чревато ошибками.
-
Нужно без них.
-
> Inovet © (20.05.16 18:46) [2]
>
> Хоть где - нейтрально, лишь бы не говнокод был.
> Dimka Maslov © (20.05.16 20:31) [4]
>
> Метки воплне допустимы там, где это помогает упростить код.
> DayGaykin © (21.05.16 04:04) [9]
>
> Соглашусь с [2]
> Eraser © (21.05.16 04:07) [10]
>
> негативно. так как в наше время метки встречаются крайне
> редко, мозг хуже воспринимает данную конструкцию, чревато
> ошибками.
> K-1000 © (21.05.16 06:26) [11]
>
> Нужно без них.
Т.е. получается что единого мнения по этому поводу нет?
Данный код пишется чисто для себя, навряд-ли он попадет к кому-то другому, разве что в виде .exe
Но просто хочется не вырабатывать у себя вредные привычки (если они действительно считаются вредными), а то потом избавиться от них не всегда просто.
-
> так как в наше время метки встречаются крайне редко, мозг
> хуже воспринимает данную конструкцию
забавная причина-следствие
-
> Т.е. получается что единого мнения по этому поводу нет?
Конечно же нет. Постоянное использование меток - действительно плохо. Но когда на один и тот же участок кода надо прийти из нескольких мест - метка куда как проще.
-
Сейчас придет Шевченко, и скажет, что за такой код положен эцих с гвоздями с занесением перед строем.
И я подпишусь.
-
Мне нравятся метки в Java. Там это не воспринимается плохо, хотя встречается тоже редко.
-
Вот удивительно, метки это значит очень плохо, а вот, например, замыкания - это хорошо, это добавляет читаемости коду? Однако чем то плохим не считается.
-
К использованию меток отношусь спокойно. К неиспользованию - тоже спокойно. Главное - не делать из этого религии.
Важны не метки (или их отсутствие), а читабельность кода. Бывают случаи, когда метки ухудшают читабельность, но бывает и когда улучшают (правда, редко).
-
Главное - чтобы костюмчик сидел! а программа - работала.
-
В принципе против меток возражений не имею. В ассемблере без меток вообще никак не обойтись. В Паскале обойтись без них можно и желательно.
Сам когда-то использовал метки в одной из своих программ (поскольку решил что так код будет короче и понятней, но теперь тоже сам не могу в нем разобраться. :)
-
Иногда можно.
Использовал один раз.
-
А ведь можно внутри while еще один while сделать или repeat. Тогда просто break.
Пользовался метками. Потом все снес. Сейчас метки только в ассемблере.
-
> dmk © (24.05.16 11:00) [22]
> А ведь можно внутри while еще один while сделать или repeat.
> Тогда просто break.
Не всегда. Недавно столкнулся примерно с такой ситуацией:
while ... do
begin
while ... do
begin
...
if ... then
// Здесь нужно прервать ВНЕШНИЙ цикл. Break не прокатывает.
goto lbl; // А вот goto - прокатывает. Просто, читабельно и элегантно.
end;
end;
lbl: ...
-
Да я не против меток, тем более в асме они повсюду ).
Где то на просторах нэта читал, что мол goto упразднят. Подумал, подумал и избавился от меток. А goto так и не убрали из языка. Кругом обман.
-
В целом - отрицательно.
Но, иногда, использую реинкарнацию процедур и функций из, скажем, Фортрана.
Дабы не корежить все - использую.
-
Если нужно выйти из нескольких циклов, я бы сделал бы выход из подпроцедуры.
-
неиспользование GOTO - это из серии Argumentum ad verecundiam -
вид ошибочной логической аргументации — предложение считать некоторое утверждение корректным потому, что такое утверждение сделано неким источником, считающимся авторитетным (wiki)
, то есть, один гуру брякнул исходя из своей субъективной нелюбви, остальные бездумно подхватили. Ни одного достойного, объективного аргумента, доказывающего вред сего, нет.
-
> K-1000 © (24.05.16 21:55) [26]
Можно и процедуру. Можно придумать еще десяток способов. Но ни один из них по простоте, читабельности и накладным расходам не сравнится с [23].
Особенно если немного изменить задачу. Допустим, требуется не прервать внеший цикл, а выйти на какой-то оператор ПЕРЕД его началом.
-
Читабельность субъективна. Любой код с goto менее читабелен, чем вариант без goto. Просто за счет того, что этот оператор очень редко используется. Приходится спотыкаться о него взглядом и думать чего же там хочет автор.
Код из начала ветки - яркий пример. Приходится его в голове повертеть, чтобы понять что имел ввиду автор. Альтернатива же без goto воспринимается сходу. Просто за счет привычки.
-
> Kerk © (25.05.16 01:03) [29]
>
> Читабельность субъективна. Любой код с goto менее читабелен,
> чем вариант без goto. Просто за счет того, что этот оператор
> очень редко используется. Приходится спотыкаться о него
> взглядом и думать чего же там хочет автор.
>
Да. Для тех кто его никогда не применял.
Для тех, кто применял и знает с чем его кушать - пример Юрий Зотов © (24.05.16 12:42) [23]
-
> Германн © (25.05.16 01:40) [30]
Предлагаю прочитать мой комментарий еще раз целиком :)
-
Код нужно писать таким образом, чтобы в каждый момент можно было держать в голове как можно меньше информации. В примере из [23] человек наткнувшийся на метку будет вынужден выяснять "а кто это у нас сюда прыгает?". Код после цикла сразу же перестает быть просто кодом, который выполняется после цикла. Линейность восприятия теряется. Появляется никому не нужная сложность.
-
> Kerk © (25.05.16 01:42) [31]
>
>
> > Германн © (25.05.16 01:40) [30]
>
> Предлагаю прочитать мой комментарий еще раз целиком :)
>
Предлагаю прочитать и мой комментарий ещё раз целиком.
А так же и ответы ЮЗ.
Чем "лесенка" кода уже, тем она лучше.
-
> человек наткнувшийся на метку будет вынужден выяснять "а
> кто это у нас сюда прыгает?".
Возле метки пишем краткий коммент - и проблема исчезла.
Кстати, ставить подобные краткие комменты по ходу выполнения прикладного функционала - тоже не вредно. Сильно облегчает понимание чужого кода, например. Или даже своего, через пару лет.
-
> Возле метки пишем краткий коммент - и проблема исчезла.
Еще лучше - дать метке осмысленное имя. Тогда и коммент может не потребоваться, метка сама все о себе скажет.
-
> Юрий Зотов © (25.05.16 01:54) [34]
>
> > человек наткнувшийся на метку будет вынужден выяснять "а
> > кто это у нас сюда прыгает?".
>
> Возле метки пишем краткий коммент - и проблема исчезла.
Об этом и речь. Комментарий написать конечно можно. Но сама необходимость написать комментарий как бы намекает нам, что с читаемостью не все в порядке.
> ставить подобные краткие комменты по ходу выполнения прикладного
> функционала - тоже не вредно
Это совсем другое. Goto и метки - это не прикладной функционал.
-
> Юрий Зотов © (25.05.16 01:58) [35]
>
> > Возле метки пишем краткий коммент - и проблема исчезла.
>
> Еще лучше - дать метке осмысленное имя.
Ну это еще куда ни шло :)
Но все равно я против goto. В основном по причинам описанным в [29]. Очень редко используется, а потому спотыкаешься взглядом и ищешь в чем подвох. Неприятное ощущение.
-
> Kerk © (25.05.16 01:59) [36]
>
>
> > Юрий Зотов © (25.05.16 01:54) [34]
> >
> > > человек наткнувшийся на метку будет вынужден выяснять
> "а
> > > кто это у нас сюда прыгает?".
> >
> > Возле метки пишем краткий коммент - и проблема исчезла.
>
>
> Об этом и речь. Комментарий написать конечно можно. Но сама
> необходимость написать комментарий как бы намекает нам,
> что с читаемостью не все в порядке.
Можно подумать что с читаемостью длинной и широкой простыни, которая не использует goto проблем не будет.
-
> Kerk © (25.05.16 02:01) [37]
Дело привычки, всего лишь.
Конечно, я против злоупотребления метками в ЯВУ (асм не в счет). Но если метка единственная, на нее идет только один переход, а сама метка стоит рядом с goto - то все в порядке.
-
> Kerk © (25.05.16 02:01) [37]
>
>
> > Юрий Зотов © (25.05.16 01:58) [35]
> >
> > > Возле метки пишем краткий коммент - и проблема исчезла.
>
> >
> > Еще лучше - дать метке осмысленное имя.
>
> Ну это еще куда ни шло :)
>
> Но все равно я против goto
А мы тебе его и не навязываем. :)
-
> Goto и метки - это не прикладной функционал.
Еще какой прикладной, если с умом комментировать! Вот пример - описание алгоритма склейки диапазонов дат на псевдокоде:
1. Отсортировать список диапазонов
2. result = false
3. i = -1
4. i++
5. Если i >= (size - 1), то выход
6. Цикл по j от (i + 1) до (size - 1) включительно
goto 4
}
И вызывать этот код в цикле, пока не вернет false.
-
полностью согласен с [29].
> Юрий Зотов © (25.05.16 02:09) [39]
> Дело привычки, всего лишь.
так и есть. лично я последний раз использовал метки году эдак в 2000-ом на паскале, будучи школьником. в Делфи уже не использовал, видимо мода на них начала проходить.
программеры более старшего поколения наверняка использовали метки в enterprise и массово, тогда это не считалось зазорным и проблем не вызывало, поэтому и выработался автоматизм.
для меня лично, на данный момент, код построенный на анонимных методах и замыканиях будет выглядеть куда понятнее, чем код на метках, хотя, работать будет очевидно медленнее.
-
> лично я последний раз использовал метки году эдак в 2000-
> ом на паскале
Вот-вот. Я не помню, когда последний раз использовал goto, при том что нет у меня установки его избегать любой ценой, совершенно. Просто не нужен. Что как бы намекает нам...
-
> Внук © (25.05.16 09:33) [43]
> Что как бы намекает нам...
... на то, что можно обойтись и без этого оператора. Это давно известно.
Однако же, можно обойтись и одним циклом while. Но почему-то никто не говорит, что циклы for и repeat - лишние.
Операции OR и XOR - тоже лишние. Достаточно иметь NOT и AND, все остальное можно построить на них. Правда, код будет чудовищным, но работать он будет верно.
Без дженериков, замыканий и анонимных функций тоже можно обойтись. Тип String - тоже лишний, поскольку есть PChar. Кстати, и типизированные указатели - тоже в топку, оставить один Pointer. Открытые и динамические массивы - тоже лишние, без них вполне жить можно. Да и комментарии - тоже не нужны, они вообще на код не влияют.
Оказывается, много чего лишнего понакручено. А зачем?
Для удобства. Для читабельности. Для снижения вероятности ошибок.
И с goto - та же история. Вот напиши такой кусок без goto - и сравним удобство и читабельность.
start:
<что-то делаем 1>
while <условие 1> do
begin
while <условие 2> do
begin
<что-то делаем 2>
if <условие 3> then
goto start;
<что-то делаем 3>
end;
<что-то делаем 4>
end;
<что-то делаем 5>
-
> Юрий Зотов © (25.05.16 10:25) [44]
Нет, намекает это нам на то, что потребность в этом операторе очень низка, и это точно не случай топикстартера.
Операторы break и continue ведь тоже частные случаи goto, я не призываю от них отказываться, ровно наоборот. А с появлением в некоторых языках операторов break и continue с меткой потребность в операторе goto вообще устремилась к нулю, потому что если его использование в циклах еще можно оправдать, то вне циклов - нет.
-
repeat
<что-то делаем 1>
while <условие 1> do
begin
while <условие 2> do
begin
<что-то делаем 2>
ПовторитьСначала := <условие 3>
if ПовторитьСначала then
Break;
<что-то делаем 3>
end;
if ПовторитьСначала then
Break;
<что-то делаем 4>
end;
until not ПовторитьСначала;
<что-то делаем 5>
-
Упс...
repeat
<что-то делаем 1>
while <условие 1> do
begin
while <условие 2> do
begin
<что-то делаем 2>
ПовторитьСначала := <условие 3>
if ПовторитьСначала then
Break;
<что-то делаем 3>
end;
if ПовторитьСначала then
Break;
<что-то делаем 4>
end;
until not ПовторитьСначала;
<что-то делаем 5>
-
Получается, что единственный аргумент - читабельность хуже.
Однако, конечным результатом программирования является программа (или результат работы программы), а не чтиво исходников.
-
крылья...хвосты...
лишь бы код читаемый был и комментов побольше, что-бы через год вспомнить о чем речь
даже если считаете что исходники вам больше не понадобятся
-
> Владислав © (25.05.16 11:09) [47]
А теперь сравним.
1. Читабельность - примерно одинаковая (хотя на мой взгляд вариант с goto для понимания проще, но пусть будет одинаково).
2. Длина кода - 14 и 18 строк.
3. Лишняя переменная ПовторитьСначала.
4. Лишние 2 проверки этой переменной.
То есть, преимуществ никаких, а недостатки есть. И ради чего? Только чтобы не писать goto?
-
> Юрий Зотов © (25.05.16 12:00) [50]
А почему пункты 2-4 отнесены к недостаткам и почему там употреблено слово "лишний"? Не потому ли, что OR и XOR, goto, String и т.д. тоже лишние? :)
-
> Юрий Зотов © (25.05.16 12:00) [50]
Все это субъективное.
1. Без goto читабельность лучше, хотя бы потому, что с goto нужно держать в уме, что тело внешнего цикла может не выполниться полностью, а явного указания этого в коде внешнего цикла нет. Кроме этого, в варианте с goto есть неявный цикл, который с ходу таковым не воспринимается. В варианте без goto этот цикл явный.
2. Длина на 4 строки больше. Если это будет 31 и 35, разница уже не кажется такой большой, а вот для варианта с goto длина уже может быть довольно большая.
3. Эта переменная как раз самодокументирует внешний цикл.
4. Их процессор выполняет, а он быстрый.
В итоге сплошные преимущества без goto. А ради чего? Только для того, чтобы уменьшить длину на 4 строки? 8-О
На мой взгляд - это все не аргументы.
Вот если бы было сказано, что процедура с goto выполняется быстрее на столько-то, что увеличивает скорость работы на столько-то, а это критично, поэтому используется вариант с goto, вот это объективный аргумент, который я бы принял, и слова бы не сказал, потому что фобий по этому поводу у меня нет.
-
> Владислав © (25.05.16 12:55) [52]
>
> Без goto читабельность лучше, хотя бы потому, что с goto
> нужно держать в уме, что тело внешнего цикла может не выполниться
> полностью, а явного указания этого в коде внешнего цикла
> нет. Кроме этого, в варианте с goto есть неявный цикл, который
> с ходу таковым не воспринимается. В варианте без goto этот
> цикл явный.
Вот это главный аргумент. Само наличие goto мгновенно усложняет код.
-
> Владислав © (25.05.16 11:09) [47]
GOTO убрали, BREAK два раза вставили. BREAK или EXIT те же GOTO по сути.
Будем уж последовательны, прервем цикл без BREAK.
-
> DVM © (25.05.16 13:45) [54]
Попробуйте обойтись в программе без инструкций семейства JMP, тогда эта претензия будет понятна.
Речь же о структуре кода. Операторы Break, Continue и функция Exit предсказуемы. Оператор Goto мало того, что способен выкинуть в произвольное место, еще и заставляет анализировать возможные побочные эффекты. Мне это не нравится.
-
> DVM © (25.05.16 13:45) [54]
"BREAK или EXIT те же GOTO по сути."
Те же, да не те же. Возьмем некий абстрактный цикл с break, и такой же с goto. Можно не смотря на код ответить, какой код начнет выполняться после break? Да. А какой код начнет выполняться после goto? Нет. Сначала надо на код посмотреть.
И еще один момент. Break нам говорит о том, что цикл завершается. Exit говорит о том, что процедура завершается. Goto не говорит ни о чем, нужно разбираться в коде.
-
-
> Внук © (25.05.16 13:57) [55]
> Владислав © (25.05.16 14:00) [56]
Вы оба правы, BREAK, разумеется, выкинет нас из цикла в предсказуемое место за циклом, но, с другой стороны, GOTO тоже нас перекидывает не в рандомное. Конечно, конец цикла найти проще, чем метку в объемной процедуре, но, с другой стороны, огромные процедуры сами по себе признак плохого кода и без меток.
На мой взгляд, если GOTO перекидывает в место, расположенное "рядом", то код от такого подхода ничуть не страдает. Мне вариант с GOTO кажется даже более понятным, т.к. чем меньше циклов тем легче воспринимать код.
-
Все еще хуже. Насколько я помню, сейчас Юрий программирует в Java, в которой нет goto вообще (я ничего не путаю?). Так что это просто зависть к нам, оставшимся верным Delphi :)
-
> а FixInsight по этому поводу что-то ищет/предупреждает ?
Нет. Надо будет добавить :)
-
> Kerk © (25.05.16 15:28) [60]
> Нет. Надо будет добавить :)
Использование GOTO не ошибка, не о чем тут предупреждать.
Не, ну можно, конечно, в предупреждении выводить "Ошибка #100500 Не совпадение с мнением Kerka-а насчет идеального кода" :)
-
> Внук © (25.05.16 15:14) [59]
В Джаве есть:
break метка
continue метка
По сути - те же goto. Причем сначала их не было, а в какой-то версии - появились. Значит, необходимость в них все же есть - и это тоже аргумент.
-
> DVM © (25.05.16 15:33) [61]
>
> > Kerk © (25.05.16 15:28) [60]
>
> > Нет. Надо будет добавить :)
>
> Использование GOTO не ошибка, не о чем тут предупреждать.
>
> Не, ну можно, конечно, в предупреждении выводить "Ошибка
> #100500 Не совпадение с мнением Kerka-а насчет идеального
> кода" :)
Так в этом же вся суть проекта! :)
Если серьезно, то кроме потенциальных ошибок там еще есть реагирование на стилевые особенности кода. Слишком длинные методы, слишком большое количество переменных, вложенные with и т.п. Goto хороший кандидат туда же. Тем более что любую проверку можно легко отключить.
-
> Юрий Зотов © (25.05.16 15:34) [62]
Так я про это написал в [45]. Операторы прерывания циклов с метками убили смысл goto совсем. Там, где они поддерживаются, конечно.
-
вот такой код
procedure TForm1.Button1Click(Sender: TObject);
label lbl;
begin
try
goto lbl;
finally
ShowMessage('1');
end;
lbl:
ShowMessage('2');
end;
у меня не компилируется, выдает ошибку
[dcc32 Error] Unit1.pas(36): E2127 'GOTO lbl' leads into or out of TRY statement, or out of FOR-IN statement whose enumerator has destructor
в вот такой
procedure TForm1.Button2Click(Sender: TObject);
var
I: Integer;
begin
for I := 0 to 10 do
begin
try
if I > 5 then
Break;
finally
OutputDebugString(PChar(I.ToString));
end;
end;
end;
компилируется.
так что label не так близок к break, continue и exit, как кажется.
-
Попробую суммировать все высказывания со своей колокольни. Goto сам по себе ничем не вреден. Он всего лишь инструмент, которым надо уметь пользоваться. Если им пользуется тот кто умеет, инструмент может иногда помочь сделать код более удобным/более читаемым/более понятным. Если им пользуются троешники, то там "как повезёт".
-
> Германн © (26.05.16 01:27) [66]
Ну вот к чему это переливание из пустого в порожнее? Ты реально думаешь, что кто-то из присутствующих в этой ветке, в том числе те, кто против использования goto, не умеют им пользоваться? В плоскости умеет/не умеет тут вопрос даже не стоит.
-
А почему никто не сказал, что на метку можно перейти из множества мест? Или в Делфи это не так?
-
> Операторы break и continue ведь тоже частные случаи goto
А если бы при помощи операторов break и continue догадались дать возможность прервать несколько циклов за раз, им бы цены не было. Но ведь мир далеко не идеален и для прерывания нескольких циклов нормальной простой и понятной альтернативы goto нет. Исключения, замыкания, анонимные методы - не панацея, лучше и проще они не сделают никогда. А вот написать Break(2) - как было бы классно. В моём собственном скриптовом языке такое реализовано и метки действительно стали вообще не нужны.
-
Dimka Maslov © (26.05.16 09:31) [69]
"А вот написать Break(2) - как было бы классно"
На мой взгляд, это намного хуже goto. Возможностей меньше, а побочные явления в циклах те же.
-
> Владислав © (26.05.16 09:39) [70]
С чего это вдруг "возможностей меньше, а побочные явления те же". Возможности те же, но "читабельность" сохраняется. Метки и переходы не нужны. Как не нужна лишняя писанина. В таких языках, как C++, где break ещё из switch выводит - вообще была бы песня.
Вот такая конструкция у меня прекрасно работает без побочных эффектов
#func check(i, j)
#if (i == 2) & (j == 2) then break(2)
#endfunc
#for i = 1 to 5
#for j = 1 to 5
#check(i, j)
#next
#next
Давайте попробуем повторить такое же в Delphi... Даже goto не поможет И не надо говорить, что у break для нескольких циклов возможностей меньше.
-
> Dimka Maslov © (26.05.16 11:03) [71]
А так будет работать?
#func check3(i, j)
#if (i == 2) & (j == 2) then break(2)
#endfunc
#func check2(i, j)
#check3(i, j)
#endfunc
#func check1(i, j)
#check2(i, j)
#endfunc
#func check(i, j)
#check1(i, j)
#endfunc
#for i = 1 to 5
#for j = 1 to 5
#check(i, j)
#next
#next
-
> Давайте попробуем повторить такое же в Delphi...
> Даже goto не поможет
Еще как поможет.
function Check(i, j: integer): boolean;
begin
result := (i = 2) and (j = 2)
end;
for i := 1 to 5 do
for j := 1 to 5 do
if Check(i, j) then
goto lbl;
lbl: ...
-
> Dimka Maslov © (26.05.16 11:03) [71]
И, кстати, Ваш подход, когда "уровень возврата" (двойка) зашит в тело самой функции, чреват ошибками. Стоит лишь вызвать ее из места, где уровень вложенности другой (не двойка). Поэтому программер, вызывая функцию, должен всегда это контролировать, а еще должен знать код функции. Все это и неудобно, и опасно.
-
Вот так и удобнее, и универсально, и безопасно:
#func check(i, j, n)
#if (i == 2) & (j == 2) then break(n)
#endfunc
#for i = 1 to 5
#for j = 1 to 5
#check(i, j, 2)
#next
#next
-
> А так будет работать?
Будет. На уровне интерпретатора это реализовано через исключение.
> Юрий Зотов © (26.05.16 11:45) [74]
Это просто пример. Обычно, всё же до таких вещей не надо доходить. Достаточно и просто прерывать не сколько циклов. А ещё бывает удобно вложенный цикл прервать, а у внешнего сразу начать новую итерацию, т.е. иметь возможность ещё continue(n) использовать. Вот тут уже никакие goto точно не помогут.
> и опасно.
Ружья куда опаснее. Но ими ведь пользуются после специальной для этого подготовки.
-
> Dimka Maslov © (26.05.16 11:52) [76]
> Вот тут уже никакие goto точно не помогут.
goto поможет всегда.
> Ружья куда опаснее. Но ими ведь пользуются после
> специальной для этого подготовки.
И время от времени успешно стреляют себе в ногу.
-
> Юрий Зотов © (26.05.16 11:50) [75]
Ну вот не вижу я ничего удобного и безопасного в этом.
Написали код:
#func check(i, j, n)
#if (i == 2) & (j == 2) then break(n)
#endfunc
#for i = 1 to 5
#for j = 1 to 5
#check(i, j, 2)
#next
#next
Прошло два года. Понадобилось после окончания внутреннего цикла выполнить некоторые действия.
Находим это:
#for i = 1 to 5
#for j = 1 to 5
#check(i, j, 2)
#next
#next
Изменяем вот так:
#for i = 1 to 5
#for j = 1 to 5
#check(i, j, 2)
#next
#Какой-то новый код
#next
Запускаем, и... Работает неправильно. Почему???
И с goto точно такая же ситуация.
Чтобы на такие грабли не наступить, достаточно не использовать такие операторы.
Ясен пень, это все мое скромное мнение. :)
-
> goto поможет всегда.
for i := 1 to 10 do begin
L:
for j := 1 to 10 do begin
for k := 1 to 10 do begin
if k = 5 then goto L;
end;
DoSomething1;
end;
DoSomething2;
end;
Изменится ли значение i после перехода на метку L, если внутри цикла k мы захотим прервать и его, и цикл j и чтобы DoSomethingи не выполнялись? Тут вообще полный этот как его произойдёт. А будь тут всего лишь Continue(3) - всё прекрасно будет.
> И время от времени успешно стреляют себе в ногу.
А это от недостатка подготовки. Мощными, но опасными предметами могут пользоваться только профессионалы, а не кто ни попадя
-
Лучше не писать программу так, чтобы поддерживать ее могли только профессионалы с опасными мощными предметами :)
Такое мое скромное мнение.
-
"В абсолют возводят только юноши. Жизнь она не только черная или белая она имеет оттенки серого."
верно как по поводу goto, так и по поводу функций по 15 строк
-
-
> Юрий Зотов © (26.05.16 12:00) [77]
> goto поможет всегда.
Кроме попытки выйти из блока try...finally путем перехода на метку как в [65]. Не компилируется даже.
-
> DVM © (26.05.16 13:10) [83]
> Кроме попытки выйти из блока try...finally путем перехода
> на метку как в [65].
Очень удачны бывают переходы в тело цикла Dо, особенно из других
модулей. Хотя трансляторы, как правило, это запрещают, их легко можно
обвести вокруг пальца, пользуясь переменными типа метки. Передача
управления в вызываемую процедуру в обход заголовка принесет вам долгие
часы счастливых раздумий над кодом завершения 0хС5.
-
Rouse_ © (26.05.16 13:13) [84]
:-D
Хорошо сказано. :)
-
> Владислав © (26.05.16 12:09) [78]
> Запускаем, и... Работает неправильно. Почему???
Потому что при вставке нового кода программист не посмотрел двумя строчками выше и не увидел, что третий параметр - двойка.
> Чтобы на такие грабли не наступить, достаточно
> не использовать такие операторы.
А с этим никто и не спорит. Конечно, лучше всего их не использовать. Речь лишь о том, что при ГРАМОТНОМ использовании они и безопасны, и позволяют упростить код, и читабельность не ухудшают.
> Rouse_ © (26.05.16 13:13) [84]
Саш, ну ты знаешь что будет, если дураку дать в руки некий стеклянный предмет...
:o)
-
Вообще, следуя логике супербезопасности, надо запретить указатели и работу с памятью. А также приведение типов, каскадное удаление в БД - и пр., и пр.
-
Ну так да. Где-то в эту сторону языки программирования и развиваются в основном. Больше типизации, меньше прямой работы с памятью. И это хорошо. Прямой доступ к памяти все равно не нужен почти никогда, а типизация чем строже, тем лучше.
Я помню когда на Coursera курс проходил про языки программирования. Там был частности ML. Так вот отдельные люди с ненавистью о нем писали. Они не могли заставить простейшие программы из 30 строк работать. Угадайте почему? Из-за строгой статической типизации.
Представляете какие программы эти люди на своих php пишут, если у них концепция статической типизации в голове не помещается?
Ограничение себя - статическая типизация, отказ от всяких goto и хаков с памятью - это что-то близкое к восточной философии. Это трудно и есть соблазн сдаться. Но если у тебя в итоге программа хотя бы запустилась, то скорее всего она будет работать :)
-
> Юрий Зотов © (26.05.16 14:40)
[87]"Вообще, следуя логике супербезопасности, надо запретить указатели и работу с памятью. А также приведение типов, каскадное удаление в БД - и пр., и пр."К такой логике вроде никто не призывал. По моему мнению, запрещать не нужно, но если можно без этого обойтись, то нужно обойтись.
А так можно дойти до подобного:
PPersonRec = ^TPersonRec;
TPersonRec = record
FirstName: string;
LastName: string;
end;
...
New(PersonRec);
...
Dispose(PersonRec);
Попробуйте переписать этот код с помощью классов, сравним удобство и читабельность.
TPerson = class
strict private
FFirstName: string;
FLastName: string;
public
property FirstName: string read FFirstName write FFirstName;
property LastName: string read FLastName write FLastName;
end;
...
Person := TPerson.Create;
...
Person.Free;
Ну вот. На три строки больше, писанины больше.
Зачем тогда класс, если конструктор, деструктор, геттеры и сеттеры не используются? ;)
-
> Владислав © (26.05.16 15:13) [89]
Опять не тот тег использовал.
PPersonRec = ^TPersonRec;
TPersonRec = record
FirstName: string;
LastName: string;
end;
...
New(PersonRec);
...
Dispose(PersonRec);
TPerson = class
strict private
FFirstName: string;
FLastName: string;
public
property FirstName: string read FFirstName write FFirstName;
property LastName: string read FLastName write FLastName;
end;
...
Person := TPerson.Create;
...
Person.Free;
-
> Зачем тогда класс, если конструктор, деструктор, геттеры
> и сеттеры не используются? ;)
Ну к примеру если у нас есть некое:
TFoo = class
FPerson: array of TPerson;
public
property Person[Index: Integer]: TPerson read GetPerson write SetPerson;
end;
то мы сможем менять любое поле каждой записи TPerson (т.к. объект).
TFoo.Person[0].FirstName := 'qwe';
А если это будет TPersonRec то менять мы сможем только запись целиком, т.е.
Tmp := TFoo.Person[0];
Tmp.FirstName := 'qwe';
TFoo.Person[0] := Tmp;
Ну либо придется переписать структуру вот таким образом:
PPersonRec = ^TPersonRec;
TPersonRec = record
private
FFirstName: string;
FLastName: string;
public
FirstName: string read FFirstName write FFirstName;
LastName: string read FLastName write FLastName;
end;
TFoo = class
FPerson: array of TPersonRec;
public
property Person[Index: Integer]: TPersonRec read GetPerson write SetPerson;
end
-
> [69] Dimka Maslov © (26.05.16 09:31)
> Break(2)
Не, ну ты вложишь когда-нибудь потом ещё один цикл, и будет тебе брик 2 не в туда. Тогда уж надо изобрести метку на именованный цикл, но ведь это раздувание семантики языка. А ради чего.
-
> [71] Dimka Maslov © (26.05.16 11:03)
> В таких языках, как C++, где break ещё из switch выводит
> - вообще была бы песня
Вот не надо гнать на Си++, как раз в нём - с этими метками всё нормально.
-
> [71] Dimka Maslov © (26.05.16 11:03)
> Вот такая конструкция у меня прекрасно работает без побочных
> эффектов
>
> #func check(i, j)
> #if (i == 2) & (j == 2) then break(2)
> #endfunc
>
> #for i = 1 to 5
> #for j = 1 to 5
> #check(i, j)
> #next
> #next
>
> Давайте попробуем повторить такое же в Delphi... Даже goto
> не поможет И не надо говорить, что у break для нескольких
> циклов возможностей меньше.
Не сомневаюсь. Но мне пришлось в эту конструкцию втыкнуть не с первого раза: как это - левая функция может вывести из цикла? А вдруг она не курит, а вдруг она не пьёт? (Функция - в смысле) А мы стакими рожами возьмём, да и припрёмся к функшен. Не, для меня это не очень привычно. Ну иногда можно, но ту как раз гоуту подойдёт.
-
> Kerk © (26.05.16 15:00) [88]
> Там был частности ML. Так вот отдельные люди
> с ненавистью о нем писали
На Паскаль я пересел с PL/1. А этот самый PL/1 вытворял чудеса. Приведение логически несовместимых типов - автоматически, например, Число = Строка (из строки берутся первые байты в количестве размера числа, и эти байты засылаются в число). Вход в цикл минуя его заголовок - запросто. Ну и т.п.
И после этой свободы - Паскаль с его строгой типизацией, представляешь? Я матерился, как шкипер пиратов. Но недолго - потому что быстро понял, как это здорово, когда компилятор страхует от потенциальных ошибок.
Я уже приводил такой пример, приведу его еще раз:
DECLARE I DECIMAL FIXED(1); // На Паскале это var I: 0..9;
DO I=0 TO 9 ... // На Паскале это for I := 0 to 9 do...
Запускаем. Программа зацикливается. Ловил 3 дня. А на Паскале сразу получил бы выход за диапазон.
-
Извиняюсь, придётся немного отложить обсуждение с моей стороны - ненадолго.
-
> Юрий Зотов © (26.05.16 19:01) [95]
"А на Паскале сразу получил бы выход за диапазон."
С чего бы? Или в примере очепятка?
-
> Владислав © (26.05.16 19:23) [97]
После последнего прохода цикла (при I=9) идет инкремент I - и получаем Range Check Error. Конечно, если этот контроль включен (а при разработке он у меня включен всегда).
-
> Юрий Зотов © (26.05.16 19:29) [98]
Можно пример, в котором это поведение проявляется?
-
Я тоже честно говоря не понял конкретный пример. Но идея понятна.
-
> Kerk © (26.05.16 19:48) [100]
Идея-то понятно, но если бы был Range Check Error с переменной цикла, это был бы большой фейл.
var
I: 0..9;
begin
for I := 0 to 9 do // Нет выхода за границы диапазона, не будет и исключения.
;
end;
-
А ведь и верно - в Delphi ошибки нет. Но в Turbo Pascal 5.5 точно была.
-
Читал ветку, читал. Но так и не понял, о чём копья ломаются.
Господа, какую проблему решаем?
-
> Юрий Зотов © (26.05.16 19:01) [95]
> Вход в цикл минуя его заголовок - запросто.
Это в PL как раз нельзя было.
Если, конечно, память не обманывает.
-
Так, начиная с [72] - всё быстро просмотрел, местами даже относительно внимательно. Похоже, пока что, добавить мне нечего.
ПС. А кто это там так боянисто вбросил? И зачем? - вот главный вопрос.:) А вы тут про метки и прочие агрегаты.:)
Если что - я тут уже давно под одним ником.
-
> Плохиш © (26.05.16 20:17) [103]
> Читал ветку, читал. Но так и не понял, о чём копья ломаются.
> Господа, какую проблему решаем?
А никакую, просто общаемся. Редкий случай, когда разговор на холиварную тему протекает в нормальном тоне.
-
> Kerk © (26.05.16 15:00) [88]
> Ну так да. Где-то в эту сторону языки программирования и
> развиваются в основном. Больше типизации, меньше прямой
> работы с памятью. И это хорошо
Насчет типизации соглашусь. Насчет работы с памятью: сборщики мусора, по-моему, зло злейшее. Жаль что эта мода врядли скоро пройдет. Думаю можно найти приемлемый способ убивать ненужные объекты сразу после выхода из зоны видимости и не использовать сборщик мусора.
-
> DayGaykin © (26.05.16 22:16) [107]
> можно найти приемлемый способ убивать
> ненужные объекты сразу после выхода из зоны видимости и
> не использовать сборщик мусора.
Его и искать не надо, он уже есть: обнулился счетчик ссылок - убили объект.
Но не все так просто. Если память, которую занимал объект просто возвратить в хип, то довольно быстро наступит такая фрагментация памяти, что получим OutOfMemory, хотя свободной памяти - до фига и больше. Надо проводить дефрагментацию паамяти, а если делать ее на каждое удаление объекта, то будет слишком накладно.
-
Кстати, интересная штука открылась (в java). Есть там метод freeMemory, который, если верить документации, просто возвращает кол-во свободной памяти в байтах. И был у меня кусок программы, который загружал дисковый файл и по нему строил в памяти список неких объектов.
Так вот - если этот файл слишком большой, то возникало то самое OutOfMemory. Тогда при отладке перед и после этого куска я вставил freeMemory с выводом в консоль - для контроля.
Ошибка тут же исчезла. Предполагаю (хотя в документации это не сказано), что внутри freeMemory сначала происходит принудительная сборка мусора и дефрагментация памяти, а уж потом возвращается ее количество.
Позже я использовал этот прием и в других похожих местах. Результат всегда был один - ошибка OutOfMemory исчезала.
-
Фатальный недостаток счетчика ссылок - циклические ссылки. Их конечно можно вручную разрывать, но не всегда просто отследить.
-
> Юрий Зотов © (26.05.16 20:05) [102]
>
> А ведь и верно - в Delphi ошибки нет. Но в Turbo Pascal
> 5.5 точно была.
>
Юр, не было. TP 5.5 у меня под рукой. До сих пор использую. Пришлось даже VMWare установить.
Точнее, если и была, то не в совсем таком коде. Да после итерации счетчик цикла сначала увеличивается, а затем проверяется условие цикла. Но это не должно приводить к ошибке.
-
> Германн © (27.05.16 01:10) [111]
Поставь опции (или птички):
{R+}
{Q+}
{O-}
и сбилди проект.
-
> Kerk © (27.05.16 00:41) [110]
> Фатальный недостаток счетчика ссылок - циклические ссылки.
>
ну в новой версии сделали weak reference, правда это само по себе несколько портит концепцию подсчета ссылок.
-
Да, это самая важная фича со времен дженериков по-моему :)
-
Самое интересное, что в "Модула-2" GOTO убрали. :)
-
> А если это будет TPersonRec то менять мы сможем только запись
> целиком, т.е.
Это следствие дизайна дельфи, который гласит: "за любое удобство нужно платить производительностью".
В плюсах, и кстати в следующей версии C#, то что ты хочешь можно и для структур со свойствами сделать.
-
> Юрий Зотов © (27.05.16 05:07) [112]
>
> > Германн © (27.05.16 01:10) [111]
>
> Поставь опции (или птички):
> {R+}
> {Q+}
> {O-}
> и сбилди проект.
>
Юр. Поставил/снял птички/галочки R и O и сбилдил проект. Птичку/галочку Q не нашел в Options. Поставил в коде явно.
program Test;
var i : 0..9;
begin
for i:=0 to 9 do
end.
Никаких сообщений об ошибках не получил.
-
Ну т.е. {$Q+}.
-
> Юрий Зотов © (26.05.16 23:09) [109]
> Результат всегда был один - ошибка OutOfMemory исчезала.
Мне кажется, если в программе возникает OutOfMemory - это повод задуматься об алгоритмах и архитектуре программы, а не добавлять недокументированные костыли.
Может я конечно не прав и в мире Java все не так.
-
> DVM © (29.05.16 11:48) [119]
> Мне кажется, если в программе возникает OutOfMemory - это
> повод задуматься об алгоритмах и архитектуре программы,
> а не добавлять недокументированные костыли.
> Может я конечно не прав и в мире Java все не так.
Прав, естественно. Только ошибку сначала надо локализовать, не так ли?
-
> Юрий Зотов © (29.05.16 12:34) [120]
> Только ошибку сначала надо локализовать, не так ли?
Разумеется, причем все такие места, т.к. их может быть не одно. Но как в этом поможет упомянутая freeMemory мне правда не понятно. Она скорее даже навредит, замаскировывая проблему. Плюс ее вызов, вероятно, приводит к некоторому замедлению работы программы из-за принудительной сборки мусора, если таковая имеет быть.
-
> Юрий Зотов © (26.05.16 23:09) [109]
>
Интересно, почему Java сама не сделала сборку мусора, когда память закончилась.
-
> Но как в этом поможет упомянутая freeMemory мне правда не
> понятно.
Надо же было как-то понять, где конкретно съедается много памяти.
> Плюс ее вызов, вероятно, приводит к некоторому замедлению
> работы программы и
При отладке это не имеет значения.
> почему Java сама не сделала сборку мусора,
Сам удивился.
-
Заставь дурака Богу молиться, он и лоб расшибёт.
Это относится как к ярым противникам goto, так и ярых его сторонников.
Причём, к сожалению, вторых я не видел. А то я хотя бы понял, с кем тут борятся )
-
> Интересно, почему Java сама не сделала сборку мусора, когда
> память закончилась.
Сборка мусора имеет наименьший приоритет, поэтому она выполняется в моменты, когда программе ну совсем нечем заняться. Кстати, об этом в документации и по яве и по визуальной студии написано.
В общем-то, по этой причине и сделаны функции принудительного запуска сборщика.
-
> поэтому она выполняется в моменты, когда программе ну совсем
> нечем заняться
то есть такой простой код
while(true)
на джаве с аут оф мемори упадет?
-
> Сборка мусора имеет наименьший приоритет
в отдельном потоке он
> то есть такой простой код
> while(true) { new Object(); }
> на джаве с аут оф мемори упадет?
нет, такой упадет:
ArrayList list = new ArrayList();
while(true) {
list.add(new Object());
}
-
Плохиш © (30.05.16 00:47) [125]
нету в Java принудительной сборке
есть gc(), но ее вызов НЕ ГАРАНТИРУЕТ запуска сборщика