Комментарии 157
Neal Stephenson thinks it's cute to name his labels 'dengo'
+5
Goto Dengo :)
Криптономикон — это очень хорошая книга :)
Криптономикон — это очень хорошая книга :)
+4
Нил Стивенсон — это очень клевый автор.
-2
НЛО прилетело и опубликовало эту надпись здесь
jz и аналоги — это не goto, это if
goto — это только jmp и (внимание!) call. Отличие последней в том, что по возможен возврат на точку, откуда тебя послали.
А для высокоуровневых языков, goto — это действительно плохо, особенно если учесть, что возможны множественные точки выхода у функций.
goto — это только jmp и (внимание!) call. Отличие последней в том, что по возможен возврат на точку, откуда тебя послали.
А для высокоуровневых языков, goto — это действительно плохо, особенно если учесть, что возможны множественные точки выхода у функций.
+5
НЛО прилетело и опубликовало эту надпись здесь
Goto у языков разные. Во многих (PHP в их числе) на уровень ниже (внутрь функции, цикла) переходить нельзя.
0
если писать на чистом C (особенно для какой нибудь мелкой железки) то удобно оформлять функцию в виде
имхо это читабельней чем городить кучу вложенных ifов
int foo()
{
FILE f = NULL;
int result = 0 ;
f = fopen("somefile.txt", "r");
if ( ! f ) {
perror("fopen");
goto exit;
}
if ( rand() > 5 ) {
result = 1;
goto exit;
}
if ( rand() > 10 ) {
result = 2;
goto exit;
}
result = 3
exit:
if (f)
fclose(f);
return result;
}
имхо это читабельней чем городить кучу вложенных ifов
+3
Чистый С по современным меркам — язык низкого уровня.
+1
Конечно правильнов С использовать goto в таких случаях, ведь изначально С был задуман как красивый ассемблер.
+3
if (! f ) {
perror(«fopen»);
}
else if ( rand() > 5 ) {
result = 1;
}
else if ( rand() > 10 ) {
result = 2;
}
else {
result = 3
}
не красиво?
perror(«fopen»);
}
else if ( rand() > 5 ) {
result = 1;
}
else if ( rand() > 10 ) {
result = 2;
}
else {
result = 3
}
не красиво?
+2
на ЯВУ такое реализуется через try… finally, причем гораздо понятнее реализуется
0
просто в С нет исключений :)
+2
Можно и без кучи if-ов и без goto ;)
- int foo()
- {
- FILE f = NULL;
- int result = ;
- f = fopen("somefile.txt", "r");
-
- do {
- if ( ! f ) {
- perror("fopen");
- break;
- }
-
- if ( rand() > 5 ) {
- result = 1;
- break;
- }
-
- if ( rand() > 10 ) {
- result = 2;
- break;
- }
-
- result = 3
-
- } while (false);
-
- if (f)
- fclose(f);
-
- return result;
- }
-1
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Если имеется обширный опыт программирования, то можно пожалуйста увидеть код, который с goto, будет выглядеть, красиво и лаконично. И в который не надо будет всматриваться десять минут?
-2
<?php
begin:
echo $i++;
goto begin;
* This source code was highlighted with Source Code Highlighter.
+1
Смешно. А что-нибудь реальное?
-1
НЛО прилетело и опубликовало эту надпись здесь
for(int i = 0; i < arrayLength; ++i) { if (array[i] == 5) goto FOUND; } // doing somthing return false; FOUND: // doing somthing else return true;
-6
Конечно же, в жтом сулчае можно было обойтись флажком, например. В операторе гоуту нет ничего плохого, если использовать его с головой а не пихать везде подряд. И, опять же, если он такой плохой, почему этот оператор есть почти во всех языках?
-3
в этом случае даже без флага можно, т.к. у вас return все равно
for(int i = 0; i < arrayLength; ++i) { if (array[i] == 5) {//found // doing somthing else return true; } } //not found // doing somthing return false;
+4
Я лишь привел пример поиска. Ситуации, когда goto делает куд читабельнее и красивее есть. И поиск — это одина из вероятных ситуаций.
Сейчас вы наверное скажете, что можно разбивать на подфункции и т.п. Да можно. Но иногда возникают ситуации, когда другие решения являются менее красивыми. Конечно, можно лепить флажки, кучи условных уровней, десятки доп функций и т.п.
Нет ничего плохого в том, чтоб грамотно использовать goto. Я не сую его во все щели и мало того, в python, на котором я очень люблю писат оператора goto нет.
if (condition) { goto CANCEL; } // some code here if (another_condition) { goto CANCEL; } // some another code here return true; CANCEL: // some cleanup code return false;
Сейчас вы наверное скажете, что можно разбивать на подфункции и т.п. Да можно. Но иногда возникают ситуации, когда другие решения являются менее красивыми. Конечно, можно лепить флажки, кучи условных уровней, десятки доп функций и т.п.
Нет ничего плохого в том, чтоб грамотно использовать goto. Я не сую его во все щели и мало того, в python, на котором я очень люблю писат оператора goto нет.
+2
>Но иногда возникают ситуации, когда другие решения являются менее красивыми.
Спасибо, поржал. Попросили привести реальный код, когда это оправдано, вы привели говнокод, сказали, что это говнокод и сказали, что есть ситуации. Вас снова попросили. Вы снова привели говнокод и снова сказали, что есть ситауции. Так приведите же, наконец, саму ситуацию, а не говнокод и надпись, что ситуация есть!
Спасибо, поржал. Попросили привести реальный код, когда это оправдано, вы привели говнокод, сказали, что это говнокод и сказали, что есть ситуации. Вас снова попросили. Вы снова привели говнокод и снова сказали, что есть ситауции. Так приведите же, наконец, саму ситуацию, а не говнокод и надпись, что ситуация есть!
+4
Если нигде не ошибся, то вроде тоже самое будет:
if (!condition) {
// some code here
if (!another_condition) {
//some another code here
return true;
}
}
//some cleanup code
return false;
if (!condition) {
// some code here
if (!another_condition) {
//some another code here
return true;
}
}
//some cleanup code
return false;
0
Ой сорри:
if (!condition) { // some code here if (!another_condition) { //some another code return true; } } //some cleanup code here return false;
+1
теперь пердположим, что кондишенов пять
так?
if (!condition) { // some code here if (!another_condition) { //some another code if (!another_condition) { //some another code if (!another_condition) { //some another code if (!another_condition) { //some another code return true; } } } } } //some cleanup code here return false;
так?
0
Формально — да.
Только это все абстрактные куски кода.
Только это все абстрактные куски кода.
0
Привидите реальный пример где у вас тру возвращается только при верности 5 условий, на каждое условие вы выполняете код, а клин делаете не зависимо от сочетания условий.
Я почти уверен, что в таком случае надо рефакторить.
Я почти уверен, что в таком случае надо рефакторить.
0
Что-то у меня с русским не то =)
0
Вы когда нить писали на чистом С? Знаете, там нет исключений.
А теперь представьте себе код, который вызывает подряд n функций, каждая из которых может вернуть ошибку. Если возникла ошибка — мы прерываем выполнение кода и делаем какую-нить очистку.
В результате у нас код выглядит приблизительно вот так:
//malloc чего-нить
do
{
if(func1())
break;
if(func2())
break;
if(func3())
break;
if(func4())
break;
}while(0)
//free чего-нить
Используется do{}while(0) только из-за предубежденности против goto. Хотя данная конструкция ничем не лучше (а может даже хуже) чем goto.
Это почти реальный код для микроконтроллера. Логика парсинга пакетов и проведения платежей на POS-терминале.
Размер памяти кода ограничен, размер оперативной памяти ограничен.
Ваши предложения по рефакторингу?
А теперь представьте себе код, который вызывает подряд n функций, каждая из которых может вернуть ошибку. Если возникла ошибка — мы прерываем выполнение кода и делаем какую-нить очистку.
В результате у нас код выглядит приблизительно вот так:
//malloc чего-нить
do
{
if(func1())
break;
if(func2())
break;
if(func3())
break;
if(func4())
break;
}while(0)
//free чего-нить
Используется do{}while(0) только из-за предубежденности против goto. Хотя данная конструкция ничем не лучше (а может даже хуже) чем goto.
Это почти реальный код для микроконтроллера. Логика парсинга пакетов и проведения платежей на POS-терминале.
Размер памяти кода ограничен, размер оперативной памяти ограничен.
Ваши предложения по рефакторингу?
+2
Вот пример из linux:
int p54_read_eeprom(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; struct p54_eeprom_lm86 *eeprom_hdr; struct sk_buff *skb; size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize; int ret = -ENOMEM; void *eeprom = NULL; maxblocksize = EEPROM_READBACK_LEN; if (priv->fw_var >= 0x509) maxblocksize -= 0xc; else maxblocksize -= 0x4; skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, sizeof(*eeprom_hdr) + maxblocksize, P54_CONTROL_TYPE_EEPROM_READBACK, GFP_KERNEL); if (!skb) goto free; priv->eeprom = kzalloc(EEPROM_READBACK_LEN, GFP_KERNEL); if (!priv->eeprom) goto free; eeprom = kzalloc(eeprom_size, GFP_KERNEL); if (!eeprom) goto free; ... еще пол экрана кода ... ret = p54_parse_eeprom(dev, eeprom, offset); free: kfree(priv->eeprom); priv->eeprom = NULL; p54_free_skb(dev, skb); kfree(eeprom); return ret; }
+4
Вот кусок кода под действием предрассудков goto
function _functiob( Url: PAnsiChar; var OutBuf: PAnsiChar ): Boolean;
const
UrlExpr: PAnsiChar = '(http://)?([^/]+)(.+)';
HeaderTpl: PAnsiChar = 'GET ${3} HTTP/1.0'#13#10'Host: ${2}'#13#10'Connection: Close'#13#10#13#10;
var
S: TSocket;
R: HRegExp;
Cnt: Integer;
Buf: PAnsiChar;
BufLen, ResLen: Cardinal;
begin
OutBuf := Nil;
Result := False;
if ( Url = nil ) or ( RegComp ( UrlExpr, R ) <> RE_OK ) then
Exit;
S := INVALID_SOCKET;
try
if not RegExec( R, Url ) then
Exit;
Buf := RegMatchStr( R, 2 );
if (Buf = nil) then Exit;
S := CreateSocketAndConnect( Buf );
StrDispose( buf );
if ( S = INVALID_SOCKET ) then
Exit;
Buf := StrNew(Url);
BufLen := StrLen(Buf);
RegReplace(UrlExpr, HeaderTpl, Buf, BufLen, 1);
if (not SendSocketData(S, Buf, BufLen)) then
Exit;
ResLen := 0;
OutBuf := Nil;
BufLen := StrBufSize(Buf);
repeat
Cnt := Recv( S, Buf^, BufLen, 0 );
if Cnt > 0 then
CollectBuf(Buf^, OutBuf, ResLen, Cnt);
until (Cnt <= 0);
If (GetHTTPAnsvNFromHeader(OutBuf) <> 200) then
Exit;
BufLen := GetHeaderSize( OutBuf );
if (BufLen = 0) then Exit;
Dec ( ResLen, BufLen );
Move ( OutBuf[BufLen], OutBuf^, ResLen );
StrRealloc(OutBuf, ResLen + 1);
OutBuf[ResLen] := #0;
Result := True;
finally
if (Buf <> Nil) then StrDispose(Buf);
if (not Result) and ( OutBuf <> Nil ) then
begin
StrDispose(OutBuf);
OutBuf := Nil;
end;
if (S <> INVALID_SOCKET) then
CloseSocket( S );
RegFree( R );
end;
end;
Try..Finally+ Exit внутри блока вместо goto.
function _functiob( Url: PAnsiChar; var OutBuf: PAnsiChar ): Boolean;
const
UrlExpr: PAnsiChar = '(http://)?([^/]+)(.+)';
HeaderTpl: PAnsiChar = 'GET ${3} HTTP/1.0'#13#10'Host: ${2}'#13#10'Connection: Close'#13#10#13#10;
var
S: TSocket;
R: HRegExp;
Cnt: Integer;
Buf: PAnsiChar;
BufLen, ResLen: Cardinal;
begin
OutBuf := Nil;
Result := False;
if ( Url = nil ) or ( RegComp ( UrlExpr, R ) <> RE_OK ) then
Exit;
S := INVALID_SOCKET;
try
if not RegExec( R, Url ) then
Exit;
Buf := RegMatchStr( R, 2 );
if (Buf = nil) then Exit;
S := CreateSocketAndConnect( Buf );
StrDispose( buf );
if ( S = INVALID_SOCKET ) then
Exit;
Buf := StrNew(Url);
BufLen := StrLen(Buf);
RegReplace(UrlExpr, HeaderTpl, Buf, BufLen, 1);
if (not SendSocketData(S, Buf, BufLen)) then
Exit;
ResLen := 0;
OutBuf := Nil;
BufLen := StrBufSize(Buf);
repeat
Cnt := Recv( S, Buf^, BufLen, 0 );
if Cnt > 0 then
CollectBuf(Buf^, OutBuf, ResLen, Cnt);
until (Cnt <= 0);
If (GetHTTPAnsvNFromHeader(OutBuf) <> 200) then
Exit;
BufLen := GetHeaderSize( OutBuf );
if (BufLen = 0) then Exit;
Dec ( ResLen, BufLen );
Move ( OutBuf[BufLen], OutBuf^, ResLen );
StrRealloc(OutBuf, ResLen + 1);
OutBuf[ResLen] := #0;
Result := True;
finally
if (Buf <> Nil) then StrDispose(Buf);
if (not Result) and ( OutBuf <> Nil ) then
begin
StrDispose(OutBuf);
OutBuf := Nil;
end;
if (S <> INVALID_SOCKET) then
CloseSocket( S );
RegFree( R );
end;
end;
Try..Finally+ Exit внутри блока вместо goto.
-2
if(!condition && !another_condition && !another_condition && !another_condition) { return true; } else { return false; }
А может так? :)
+1
только там еще есть
// some code here
0
Да, комментарии-то я и упустил… однако если внутри каждого условия код — то то как они выглядят в коде имхо вполне оправданно, по уровню вложенности можно легко понять при каких конкретно условиях выполнится конкретный кусок кода, это имхо визуально гораздо более наглядно, а в случае с goto придется просматривать каждую строку досконально, потому как помимо
может быть и
if(condition) { // кусок кода, который зависит от условия // и вызывает преждевременную остановку программы goto CANCEL; }
может быть и
if(condition) { // кусок кода, который зависит от условия // но не вызывает преждевременную остановку программы }
+1
тогда уж лучше сделать что-то вроде:
if(checkConditions()) {
} else {
}
а в чек кондишнс можно уже и написать что-то вроде
return checkFirstCondotion() && checkSecondCondition() && ...;
потому как иногда условия могут и по несольку строчек быть.
if(checkConditions()) {
} else {
}
а в чек кондишнс можно уже и написать что-то вроде
return checkFirstCondotion() && checkSecondCondition() && ...;
потому как иногда условия могут и по несольку строчек быть.
0
особые извращенцы в страхе goto пишут так (и считают это хорошим стилем):
do {
if (condition)
break;
// some code here
if (another_condition)
break;
// some another code here
return true;
} while (0);
// some cleanup code
return false;
Вот по-моему уж лучше goto.
do {
if (condition)
break;
// some code here
if (another_condition)
break;
// some another code here
return true;
} while (0);
// some cleanup code
return false;
Вот по-моему уж лучше goto.
+1
>особые извращенцы в страхе goto пишут так (и считают это хорошим стилем):
…
Вот по-моему уж лучше goto.
Вы не поверите, но это не просто «считается» — это и есть хороший стиль, и мифический «страх goto» тут не при чём.
Когда читаешь код, то при использовании конструкции «do {...} while(0);» найти «точку выхода» гораздо легче, потому что она в заранее известном месте: в конце блока. При использовании goto выход может оказаться где угодно.
…
Вот по-моему уж лучше goto.
Вы не поверите, но это не просто «считается» — это и есть хороший стиль, и мифический «страх goto» тут не при чём.
Когда читаешь код, то при использовании конструкции «do {...} while(0);» найти «точку выхода» гораздо легче, потому что она в заранее известном месте: в конце блока. При использовании goto выход может оказаться где угодно.
0
Простите, а как же семантика?
Любой, кто видит конструкцию «do {...», начинает сначала вдумываться зачем тут нужен цикл, и только потом, в конце, обнаруживает "} while(0);". Это может сильно путать.
Иными словами, do… while предназначено для другого, а именно — для циклов с постусловием. И с точки зрения семантики для других целей эта конструкция не применима.
Любой, кто видит конструкцию «do {...», начинает сначала вдумываться зачем тут нужен цикл, и только потом, в конце, обнаруживает "} while(0);". Это может сильно путать.
Иными словами, do… while предназначено для другого, а именно — для циклов с постусловием. И с точки зрения семантики для других целей эта конструкция не применима.
0
Если выбирать между 100%-верной и правильной семантикой с одной стороны и читабельностью кода с другой стороны — лично я выберу второе.
Можно сколь угодно долго теоретизировать над семантикой, но в «полевом» применении код с «do {...} while(0);» читается и сопровождается намного легче — это факт.
А уж если рассуждать с точки зрения семантики и возводить всё в абсолют, то конструкция for(;;) тоже неприменима: оператор for предназначен для другого, а именно — для цикла с первичной инициализацией, условием и выполнением оператора после каждой итерации. А для бесконечного цикла надо использовать while(true). Верно? ;)
Можно сколь угодно долго теоретизировать над семантикой, но в «полевом» применении код с «do {...} while(0);» читается и сопровождается намного легче — это факт.
А уж если рассуждать с точки зрения семантики и возводить всё в абсолют, то конструкция for(;;) тоже неприменима: оператор for предназначен для другого, а именно — для цикла с первичной инициализацией, условием и выполнением оператора после каждой итерации. А для бесконечного цикла надо использовать while(true). Верно? ;)
0
> лично я выберу второе.
я не знаю ни одного примера, когда следование правилам семантики вредит читаемости кода. и наоборот, отступление от семантического порядка — всегда вредит.
>читается и сопровождается намного легче — это факт
все же — не факт. сильно запутывает, когда для решения одних задач используются конструкции, предназначенные для других задач (то есть когда нарушается семантика, не спроста же она придумана).
> А для бесконечного цикла надо использовать while(true). Верно?
while(true) действительно несколько более предпочтительно. гикам нравится использовать for(;;) только потому, что это на несколько символов короче.
но нужно помнить, что с точки зрения семантики while(true) — все равно не идеально, так как это цикл с предусловием, которого в случае вечного цикла получается что нет.
то есть с точки зрения семантики было бы логично ввести специальную конструкцию для вечных циклов, скажем, loop {… }.
но этого нет и не будет, потому что, помимо всего прочего, в идеале, вечных циклов в реальных программных продуктах вообще не должно быть (тема для нового холивара?), но это уже другая тема…
я не знаю ни одного примера, когда следование правилам семантики вредит читаемости кода. и наоборот, отступление от семантического порядка — всегда вредит.
>читается и сопровождается намного легче — это факт
все же — не факт. сильно запутывает, когда для решения одних задач используются конструкции, предназначенные для других задач (то есть когда нарушается семантика, не спроста же она придумана).
> А для бесконечного цикла надо использовать while(true). Верно?
while(true) действительно несколько более предпочтительно. гикам нравится использовать for(;;) только потому, что это на несколько символов короче.
но нужно помнить, что с точки зрения семантики while(true) — все равно не идеально, так как это цикл с предусловием, которого в случае вечного цикла получается что нет.
то есть с точки зрения семантики было бы логично ввести специальную конструкцию для вечных циклов, скажем, loop {… }.
но этого нет и не будет, потому что, помимо всего прочего, в идеале, вечных циклов в реальных программных продуктах вообще не должно быть (тема для нового холивара?), но это уже другая тема…
0
>я не знаю ни одного примера, когда следование правилам семантики вредит читаемости кода. и наоборот, отступление от семантического порядка — всегда вредит.
Т.е. текущий пример с goto Вам не нравится?
Вы отойдите от теории и спуститесь на землю: вот читаю я чей-то код, тут мне попадается «goto some_label;» — и где я её должен искать? Запускать поиск? Скроллить и пытаться поймать глазами? И хрен с ним, что неудобно искать — зато, панимашь, семантически верно, да?
А вот если стоит do {...} while(false), то я знаю наверняка, куда мы попадём после break: в конец блока, который видно даже невооружённым беглым взглядом, кинутым по диагонали. Будете спорить?
Может быть, всё же стоит убавить градус категоричности в своих заявлениях?
Т.е. текущий пример с goto Вам не нравится?
Вы отойдите от теории и спуститесь на землю: вот читаю я чей-то код, тут мне попадается «goto some_label;» — и где я её должен искать? Запускать поиск? Скроллить и пытаться поймать глазами? И хрен с ним, что неудобно искать — зато, панимашь, семантически верно, да?
А вот если стоит do {...} while(false), то я знаю наверняка, куда мы попадём после break: в конец блока, который видно даже невооружённым беглым взглядом, кинутым по диагонали. Будете спорить?
Может быть, всё же стоит убавить градус категоричности в своих заявлениях?
0
>> А вот если стоит do {...} while(false), то я знаю наверняка, куда мы попадём после break: в конец блока, который видно даже невооружённым беглым взглядом, кинутым по диагонали.
Как метка так и конец блока могут как быть так и не быть в пределах досягаемости беглого взгляда. Метка хороша тем, что это не какая-то безликая скобочка и ее можно найти поиском. И она не уйдет со своего места, если кто-нибудь захочет поместить внутрь do {} while(0) вложенный цикл, по случаю охватывающий и ваш break.
Как метка так и конец блока могут как быть так и не быть в пределах досягаемости беглого взгляда. Метка хороша тем, что это не какая-то безликая скобочка и ее можно найти поиском. И она не уйдет со своего места, если кто-нибудь захочет поместить внутрь do {} while(0) вложенный цикл, по случаю охватывающий и ваш break.
0
>Как метка так и конец блока могут как быть так и не быть в пределах досягаемости беглого взгляда.
При скролле глаз цепляется за изменение уровня вложенности куда легче, чем за текстовую метку.
>И она не уйдет со своего места, если кто-нибудь захочет поместить внутрь do {} while(0) вложенный цикл, по случаю охватывающий и ваш break.
Вдруг откуда ни возьмись случайно взялся вложенный цикл? :)
Ну извините, тут мне действительно нечего возразить…
В общем, я свои аргументы привёл, а уж решать, весомые они или нет — личное дело каждого.
При скролле глаз цепляется за изменение уровня вложенности куда легче, чем за текстовую метку.
>И она не уйдет со своего места, если кто-нибудь захочет поместить внутрь do {} while(0) вложенный цикл, по случаю охватывающий и ваш break.
Вдруг откуда ни возьмись случайно взялся вложенный цикл? :)
Ну извините, тут мне действительно нечего возразить…
В общем, я свои аргументы привёл, а уж решать, весомые они или нет — личное дело каждого.
0
for(;;)
{
echo $i++;
}
+2
while(1)
{
echo $i++
}
{
echo $i++
}
+2
вопрос стилевых предпочтений.
я предпочитаю кодировать infinite loop как for(;;).
я предпочитаю кодировать infinite loop как for(;;).
0
while(1) это классический пример бесконечного цикла
Хотя кому как больше нравится ;)
Хотя кому как больше нравится ;)
+2
И часто Вам приходится кодировать infinite loop?:)
-1
Как ни странно, но приходилось. =) Давно это было и не правда. Даже не помню зачем.
0
Для демонов различного рода достаточно обычный код.
+1
Спасибо. Я сам не додумался чего-то. Возможно для вечно работающих сервисов — самое оно.
Хотя звучит как-то все равно коряво. Ведь должны же быть какие-то возможность остановки. Т.е. нужно в цикл этот передать событие, которые остановит этот цикл.
Думаю, что для этого конструкция for(;;) врядли подойдет — вот while(boolen) как-то красивее смотрится…
Хотя звучит как-то все равно коряво. Ведь должны же быть какие-то возможность остановки. Т.е. нужно в цикл этот передать событие, которые остановит этот цикл.
Думаю, что для этого конструкция for(;;) врядли подойдет — вот while(boolen) как-то красивее смотрится…
0
for (;; print($i++)) {}
+3
while(print $i++);
+3
Классика:
for(int i = 0; i < M; ++i)
for(int j = 0; j < N; ++j)
{
do_something();
if(some_condition())
goto exit;
}
exit:;
Попробуйте написать это лаконично и красиво БЕЗ goto.
for(int i = 0; i < M; ++i)
for(int j = 0; j < N; ++j)
{
do_something();
if(some_condition())
goto exit;
}
exit:;
Попробуйте написать это лаконично и красиво БЕЗ goto.
-1
меня Ваш и все выше примеры подталкивают, что спор не про goto, а про ООП и процедуры, что попахивает холиваром :)
в вашем случае вместо goto exit — return; потому что код внутри метода.
понадобился goto внутри одного метода? — рефакторинг.
в вашем случае вместо goto exit — return; потому что код внутри метода.
понадобился goto внутри одного метода? — рефакторинг.
+1
Я вот что думаю: никто же не говорит, что break (AKA exit for) — это плохо. Есть такое понятие (чисто концептуально): выход из цикла. Так уж сложилось, что традиционные языки вроде С++ поддерживают выход из цикла только на один уровень вверх (ниже пишут, что в Javascript и РНР можно и на два уровня).
Возможно, здесь можно выделить метод, сделать рефакторинг и т.п., но не будем заставлять телегу бежать впереди лошади. Предположим, у меня есть алгоритм с циклом посередине. Я не хочу рефакторинга, пусть будет в одной процедуре. Из цикла выходим с помощью break. Теперь у меня есть вложенный цикл. По сути это то же самое — цикл + выход из него. Здесь нужно делать реорганизацию кода лишь из-за того, что язык не позволяет выйти из вложенного цикла?! :)
Возможно, здесь можно выделить метод, сделать рефакторинг и т.п., но не будем заставлять телегу бежать впереди лошади. Предположим, у меня есть алгоритм с циклом посередине. Я не хочу рефакторинга, пусть будет в одной процедуре. Из цикла выходим с помощью break. Теперь у меня есть вложенный цикл. По сути это то же самое — цикл + выход из него. Здесь нужно делать реорганизацию кода лишь из-за того, что язык не позволяет выйти из вложенного цикла?! :)
+1
Вы правильный вопрос задали, как я выше написал — мы на грани холивара. :)
return из inline функций, тоже можно расценивать как goto :)
break — это, фактически, тот же goto, с этим я согласен и потому стараюсь им не пользоваться. во всяком случае, каждый раз, когда мне приходит в голову использовать break я оцениваю код — не пришло ли время рефакторинга.
на самом деле, я считаю, что вопрос использовать goto или нет — в основном (но не только), удобство работы в команде, т.е. читаемость Вашего кода другими разработчиками, без Вашего участия. если не использовать «goto vpizdu», т.е. не всегда очевидно куда :), возможно такие конструкции бывают понятны и уместны, но, как видно из практики вообще и из этого топика в частности, большинство разработчиков goto воспринимают негативно.
ps: например, мне за ~8 лет работы ни разу не пришлось/захотелось написать goto, хотя, возможно, это мои предрассудки.
return из inline функций, тоже можно расценивать как goto :)
break — это, фактически, тот же goto, с этим я согласен и потому стараюсь им не пользоваться. во всяком случае, каждый раз, когда мне приходит в голову использовать break я оцениваю код — не пришло ли время рефакторинга.
на самом деле, я считаю, что вопрос использовать goto или нет — в основном (но не только), удобство работы в команде, т.е. читаемость Вашего кода другими разработчиками, без Вашего участия. если не использовать «goto vpizdu», т.е. не всегда очевидно куда :), возможно такие конструкции бывают понятны и уместны, но, как видно из практики вообще и из этого топика в частности, большинство разработчиков goto воспринимают негативно.
ps: например, мне за ~8 лет работы ни разу не пришлось/захотелось написать goto, хотя, возможно, это мои предрассудки.
+1
Да, холивар — штука опасная :) В принципе, конечно, главное — читабельность. В конце концов, если Вам не нравится goto, сделаете рефакторинг, но код с выходом за пределы двойного цикла тоже понятен сразу — и даже если Вы сами его не пишете, другого поймёте.
А методологии… ээх, в большинстве учебников по С++ сейчас пишут: нигде и никогда не используйте препроцессор! При этом открываешь boost, и видишь, что половина его написана на чистом препроцессоре :)
А методологии… ээх, в большинстве учебников по С++ сейчас пишут: нигде и никогда не используйте препроцессор! При этом открываешь boost, и видишь, что половина его написана на чистом препроцессоре :)
0
Не знаю, красиво это, или некрасиво, я в таких случаях всегда выставляю флаг. Его еще можно как-нибудь понятно назвать.
+1
Ну так приведите код — подозреваю, будет неприятная бодяга с двумя break-ами.
0
Что-то типа такого:
exit_flag = False while(!exit_flag) { while(!exit_flag) { .... exit_flag = True; break; .... } }
0
Да, но у вас пропал цикл с перебором i и j. Если их добавить, получится куда грустнее и объемнее.
0
Вообще-то я всегда ставил строчку:
Но вот буквально сейчас подумал, что ведь наверное можно и так:
for(... if(!exit_flag) { break; }
Но вот буквально сейчас подумал, что ведь наверное можно и так:
exit_flag = False; for(i=0;i++;i<10 && !exit_flag) { if(!exit_flag) { break; } for(j=0;j++;j<10 && !exit_flag) { ... exit_flag = True; ... } }
0
Ну что ж, здесь я сдаюсь. Чудес не бывает. Приведённый Вами код и есть лучшее, что можно сделать без goto. Но красивее и лаконичнее ли он моего? На мой взгляд — нет. Мне кажется, goto для выхода из двойного цикла читается лучше этого варианта с флагом. А главное (!) зачем? Только ради того, чтобы избавиться от «неправильного» оператора.
+1
Да я не спорю, просто делюсь опытом. Для меня, мой метод — это стандарт. Работает во всех почти во языках.
А goto я не применяю. В сложных случаях я всегда применяю флаги с читабельными названиями.
Цель — максимально повысить читабельность кода. На мой взгляд в последнем примере хорошо то, что в строке for сразу и в одном месте видны все условия, по которым производится выход из этого цикла.
А goto я не применяю. В сложных случаях я всегда применяю флаги с читабельными названиями.
Цель — максимально повысить читабельность кода. На мой взгляд в последнем примере хорошо то, что в строке for сразу и в одном месте видны все условия, по которым производится выход из этого цикла.
0
Приношу извинения. Забыл убрать строчку с if(), в предыдущем сообщении следует читать:
exit_flag = False; for(i=0;i++;i<10 && !exit_flag) { for(j=0;j++;j<10 && !exit_flag) { ... exit_flag = True; ... } }
0
Добавил: Причем break нужен только тогда, если хотим, чтобы операторы после выставления флага не выполнялись. Обычно можно совсем без брейков.
0
break 2
0
Если бы вы знали язык на котором пишете, то наверняка бы вспомнили, что есть такая чтука как break, которой можно указать сколько цикцлов или структур switch, из которых надо выйти:
Почитайте доки, они полезны.
for($i = 0; $i < 10; $i++) { for($j = 0; $j < 10; $j++) { $result = $i*10 + $j; var_dump($result); if($result == rand(0, 99)) { break 2; } } }
Почитайте доки, они полезны.
+1
Я не пишу на РНР — мне кажется, данная ветка обсуждения уже слегка выходит за пределы конкретных языков. Да, в РНР можно так, но мало где ещё можно.
+1
Не вижу чем это лучше GOTO при выходе из двойного цикла? А если тройной и т.п.? Когда читаю ваш код, я буду отсчитывать два цикла назад, искать конец блока внешнего цикла. Здесь конечно всё очевидно, но бывает куда больше строк кода в обоих циклах, что можно сильно запутаться. А тут раз и условие, переходим в метку и читаем код дальше. Согласен, что этот пример куда лучше чем с флагами, но всё-же.
-1
Полуркай linux kernel
0
Странно, что на динозавре нет наездника-нациста.
+18
В asm без goto будет тяжело ;)
А для PHP — это зло
А для PHP — это зло
-3
Что же тогда сказать о PHP-GTK?
-2
А я за goto. Фильтровать быдлокодеров.
Открыл код, увидел goto, послал нах. Если конечно знаешь, как сделать без goto.
Открыл код, увидел goto, послал нах. Если конечно знаешь, как сделать без goto.
-13
НЛО прилетело и опубликовало эту надпись здесь
возможно, предложение не согласовано :))
(с) Майкрософт Ворд
(с) Майкрософт Ворд
+23
человек пошутил, а вы его заминусовали:) лично мне его сарказм понравился:)
0
человек пошутил, а вы его заминусовали:) лично мне его сарказм понравился:)
0
Помню где-то раздобыли часть исходников виндовса, в которых я нашел строку «goto vpeezdoo»
+1
<+cyth> loonysalmon, here is the rule, if you have to ask about goto, forget it exists
© ##php @ irc.freenode.net, только что
© ##php @ irc.freenode.net, только что
0
Для выхода из нескольких вложенных циклов считаю вполне допустимым использовать goto.
+7
О, догматики уже минусов понаставили :-)
Использование goto для выхода из нескольких вложенных циклов — нормальная практика.
stackoverflow.com/questions/324831/breaking-out-of-a-nested-loop
Нельзя догматично отвергать goto. Этот оператор есть во всех языках, где он нужен.
Надо просто понимать, в каких (редких) случаях стоит его использовать.
Дональд Кнут целую большую статью написал по этому поводу. Догматикам советую почитать на досуге для развития способности критически мыслить: http://pplab.snu.ac.kr/courses/adv_pl05/papers/p261-knuth.pdf (PDF).
Использование goto для выхода из нескольких вложенных циклов — нормальная практика.
stackoverflow.com/questions/324831/breaking-out-of-a-nested-loop
Нельзя догматично отвергать goto. Этот оператор есть во всех языках, где он нужен.
Надо просто понимать, в каких (редких) случаях стоит его использовать.
Дональд Кнут целую большую статью написал по этому поводу. Догматикам советую почитать на досуге для развития способности критически мыслить: http://pplab.snu.ac.kr/courses/adv_pl05/papers/p261-knuth.pdf (PDF).
+10
Эм… Возможно, что я не понял вашей великой мысли… Но нельзя ли в вашем примере, переписанном на PHP (ведь мы сейчас о нем говорим, да?), просто использовать циферки, соответствующие вложенности? Навроде этого:
while(true) {
while(true) {
break 2;
}
}
А вообще по теме — кто захочет написать код, в котором невозможно разобраться, у того это получится и без goto :-)
while(true) {
while(true) {
break 2;
}
}
А вообще по теме — кто захочет написать код, в котором невозможно разобраться, у того это получится и без goto :-)
+6
Ну тут уже дискуссия не только про PHP пошла.
А про break «levels» в PHP не знал, каюсь :-) Ибо не использую PHP практически.
А про break «levels» в PHP не знал, каюсь :-) Ибо не использую PHP практически.
+2
break 2 это ещё большее зло, чем goto наружу цикла. Программист не обязян уметь считать уровни вложенности, к тому же при рефакторинге их количество может измениться.
Более-менее правильно сделано в жаваскрипте:
Более-менее правильно сделано в жаваскрипте:
top: while(true) { while(true) { break top; } }
0
Подумалось… Вот именно в такой ситуации, break N ещё более великое зло, чем goto.
Объясняю: если указан goto somewhere, то вне зависимости от дальнейших модификаций кода, goto somewhere будет выходить именно на somewhere, а не куда-то ещё.
А вот break N в случае добавления/убирания циклов будет выкидывать не туда, куда надо, и такую ошибку очень легко допустить, особенно если код циклов достаточно большой, а не три строчки как в вышеприведённых примерах.
Так что в плане дальнейшей поддержки кода goto выглядит привлекательнее, чем break N.
Хотя лично сам goto в php никогда не использовал и не имел даже такого побуждения. Как-то код всегда рефакторился в удобочитаемый вид без подобных выкрутасов.
Объясняю: если указан goto somewhere, то вне зависимости от дальнейших модификаций кода, goto somewhere будет выходить именно на somewhere, а не куда-то ещё.
А вот break N в случае добавления/убирания циклов будет выкидывать не туда, куда надо, и такую ошибку очень легко допустить, особенно если код циклов достаточно большой, а не три строчки как в вышеприведённых примерах.
Так что в плане дальнейшей поддержки кода goto выглядит привлекательнее, чем break N.
Хотя лично сам goto в php никогда не использовал и не имел даже такого побуждения. Как-то код всегда рефакторился в удобочитаемый вид без подобных выкрутасов.
+1
в php есть goto? :-)
+2
5.3
0
Зачем они его добавили, они мотивировали? :)
0
Видимо у них есть отличный план. Чего только стоит их предыдущий перл про выбор названия для "::" (двойного двоеточия):
«Paamayim Nekudotayim» на первый взгляд может показаться странным словосочетанием для обозначения двойного двоеточия. Однако, во время создания Zend Engine версии 0.5 (который входил в PHP3), Andi и Zeev выбрали именно это обозначение. «Paamayim Nekudotayim» действительно значит «двойное двоеточие». На иврите. Просто это обозначение не менялось ни разу в течение всего времени разработки PHP.
+3
НЛО прилетело и опубликовало эту надпись здесь
Не чоень понятно, при чём тут вообще PHP и создатели его документации :)
+2
это все питонисты и рубисты завидуют, у них то goto нет!
+1
А ещё там нет «break 2»
0
в питоне есть, но в виде шутки. entrian.com/goto/
Предостережение вверху статьи радует:)
Предостережение вверху статьи радует:)
0
и в ruby есть, вот пример из книги The ruby programming language
0
боян
-4
Вспомнился случай с первого курса:
Нам читали С. Чувак намутил прогу, а там GOTO. Препод говорит: плохой стиль, перепеши — тогда я приму. А он в программировании null (как и преподша вообщем). Он взял и табом позаганял метки за пределы экрана, и к преподше… Зачет.
ЗЫ. Преподшу поменяли только год назад, это через 6 лет после того случая. Весь факультет знал, что она тупая.
Нам читали С. Чувак намутил прогу, а там GOTO. Препод говорит: плохой стиль, перепеши — тогда я приму. А он в программировании null (как и преподша вообщем). Он взял и табом позаганял метки за пределы экрана, и к преподше… Зачет.
ЗЫ. Преподшу поменяли только год назад, это через 6 лет после того случая. Весь факультет знал, что она тупая.
+1
Ну вот, зачем сказали, что он там теперь есть? Я расстроен.
+1
Что-то мне уже давно не приходилось видится с goto, с тех пор как освоил ООП и структурное программирование. Да и необходимости даже не было.
P.S. Как никак, без goto уже обхожусь 3 года. Вспоминаю страшные программы однокурсников по паскалю, где этих goto было не счесть.
P.S. Как никак, без goto уже обхожусь 3 года. Вспоминаю страшные программы однокурсников по паскалю, где этих goto было не счесть.
0
НЛО прилетело и опубликовало эту надпись здесь
Holy war never changes…
0
Вот хаете тут, а никто даже не посмотрел или не упомянул, что goto в PHP имеет следующие ограничения:
1). Нельзя выпрыгнуть за пределы цикла и case'ов.
2). Возвращатся НЕЛЬЗЯ, т.е. перейти на метку можно только вперёд по потоку выполнения программы. Т.е. бесконечные циклы с помощью goto — забудте.
1). Нельзя выпрыгнуть за пределы цикла и case'ов.
2). Возвращатся НЕЛЬЗЯ, т.е. перейти на метку можно только вперёд по потоку выполнения программы. Т.е. бесконечные циклы с помощью goto — забудте.
+4
GOTO снова в моде :-)
Все новое — хорошо забытое старое.
Все новое — хорошо забытое старое.
-1
Исходники ядра linux не хило нашпингованы оперетором goto
+2
О-о, холивар такой холивар :)
+1
НЛО прилетело и опубликовало эту надпись здесь
В php достаточно языковых конструкций для того чтобы полностью исключить использование оператора goto, и все слюнопускательства по поводу «а вот в ассемблере, а вот в си, а вот в...» — пустая болтология, вот пусть в языках где единственная возможность выйти из вложенного цикла — это goto — его и вводят, благо в php такая возможность есть и без goto, а еще функции/методы, исключения и иже с ними, которые все вместе с лихвой покрывают необходимость в goto.
+2
Плюс один. Зато у говнокодеров появится ещё больше возможностей испортить код, а у критиков — попенять на то, что php-шники не умеют нормально программировать.
Нормальные языки _помогают_ писать хорошие программы, а PHP своей бездарной архитектурой провоцирует писать говнокод… Только теперь он будет банановый — с goto.
Нормальные языки _помогают_ писать хорошие программы, а PHP своей бездарной архитектурой провоцирует писать говнокод… Только теперь он будет банановый — с goto.
+2
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
GOTO