Использование операторов break & continue
Using break and continue is not allowed in any of your code for this class. Using these statements damages the readability of your code. Readability is a quality necessary for easy code maintenance.Там похоже подбираются задания такие, что можно понятно и лаконично написать без break/continue. continue вообще не помню, когда последний раз пользовался.
Чем плох такой код и как его правильно написать, чтобы он отвечал современным стандартам?Я бы написал как минимум так (зачем там continue неясно совершенно):
for (i = 0; i < LEN; i++)
{
if (check_cond (condArr[i]) && valArr[i] == CONST)
break;
}
Еще варианты: выделить в фунцкию и делать return из цикла и return после функции на случай, если не нашлось (это, кстати, принятый в питоне способ выскакивать из двух вложенных циклов: рефакторинг выделение функции).
Нет, неправда. Это как раз в силу уродства питона в плане выбора синтаксиса.
Если бы "break" и "continue" требовали метку цикла, как это сделано в Аде,
то код был бы хотя бы минимально воспринимаемым, а без меток не всегда
понятно, откуда именно выходит "break" и что именно продолжает "continue".
---
...Я работаю...
Чем плох такой код и как его правильно написать, чтобы он отвечал современным стандартам?всякий continue
for (..)
if (условие)
code1;
continue;
code2;
можно переписать как:
for (..)
if (условие)
code1;
else
code2;
а break?
> break;
В сях, кстати, этот недостаток проявляется в полный рост,
так как "break" применяется не только к операторам циклов,
а ещё к ветвлению и составному оператору, но к последнему ---
"только по праздникам."
> (это, кстати, принятый в питоне способ выскакивать из двух вложенных
> циклов: рефакторинг выделение функции
И всё из-за того, что питон убог.
---
...Я работаю...
[i for i in range(min(len(valArr len(check_cond if valArr[i] == COND and check_cond (condArr[i])]
Без выхода на первом элементе, но наверное можно на итераторах сделать, язык не родной
без меток не всегдаIDE же показывает
понятно, откуда именно выходит "break" и что именно продолжает "continue".
Я бы написал как минимум так (зачем там continue неясно совершенно):Ну отчасти как раз для удобства восприятия
Кмк
if (!condFunc1(... continue; // my comment
if (!condFunc2(... continue; // my another comment
if (!condFunc3(... continue; // nice comment
воспринимается лучше чем
if (condFunc1(...) && condFunc2(...) && condFunc3(...) && testVar == CONST) {...}
особенно, когда названия функций и переменных в аргументах не такие лаконичные, а в целом такой if занимает несколько строк, чтобы умещаться на экране.
if( ... ) {
...
} else {
...
}
Писать
if( ... ) {
return ...;
}
...
Это упрощает чтение.
Та же идея может пройти с continue, если это в самом начале и ветка короткая.
if (condFunc1(...) // my comment
&& condFunc2(...) // my another comment
&& condFunc3(...) // nice comment
&& testVar == CONST) {...}
Но я согласен, иногда может быть нужно (я написал выше, когда это условие явно короче, чем остальной код).
return после функции на случай, если не нашлосьТак?
tttt f
{
for (i = 0; i < LEN; i++)
{
if (check_cond (condArr[i]) && valArr[i] == CONST)
return i;
}
return xxx;
}
Что надо написать вместо ttt и xxx?
а break?через внешнюю переменную
for(условие)
{
if (условие1)
break;
code;
}
преобразуется в
var isContinue = true;
for(условие && isContinue)
{
if (условие1)
isContinue = false;
else
code;
}
ps
cложные преобразования начинаются, когда if с continue/break засунут во внутрь еще в несколько if-ов. Это потребует разворачивание if-ов
как мне недавно показали, в питоне есть goto, и импорт его в рабочую область не сложен. Так что если запрещают break && continue - делай goto на метку, метка намного более наглядна
for i in range(LEN):
if check_cond(condArr[i]) and valArr[i] == CONST:
print "We found i = %d" % i
break
else:
print "Not found"
И оно правильно предупреждает тебя, что ты перенёс кусок кода,
где есть такой "break"?
---
...Я работаю...
Во многих стайлгайдах для написания функций при наличии короткой ветки предлагается вместомне лично continue/break нравится. с ними код получается короче.
и с ходу мне сложно представить код, когда continue/break создают нечитаемость
ttt = int option
xxx = NONE
---
"Vyroba umelych lidi, slecno, je tovarni tajemstvi."
и с ходу мне сложно представить код, когда continue/break создают нечитаемостьнесколько вложенных циклом на пару экранов. Можно элементарно заблудиться
несколько вложенных циклом на пару экранов. Можно элементарно заблудитьсяв коде на несколько экранов легко заблудиться и без continue/break
имхо, скорее надо бороться с кодом на несколько экранов, чем с continue/break;
тем более, что IDE может показывать, какое continue/break какому циклу соответствует
несколько вложенных циклом на пару экранов. Можно элементарно заблудитьсяТут проблема не только в continue/break будет.
И оно правильно предупреждает тебя, что ты перенёс кусок кода,если для переноса используешь пункты меню "Рефакторинг", то, да, предупредит.
где есть такой "break"?
Если просто переносишь текст, то что если имена меток совпали?
Так что если запрещают break && continue - делай goto на метку, метка намного более наглядна
тэг [sarcasm] да?
for (i = 0; i < LEN; i++)
{
if (check_cond (condArr[i]) && valArr[i] == CONST)
break;
}
Для начала, кусок кода у топик-стартера и этот — это C, а не Python.
Далее, если уж так хочется избавиться от break (причины не рассматриваю то можно условие в цикл ввести, типа
for (i = 0; i < LEN && valArr[i] != CONST; i++)
{
if (check_cond (condArr[i] {
…
}
}
(x for x in range(0, LEN) if condArr[x] and valArr[x] == CONST).next
читаемость конечно суперская
исключение еще придется ловить
Хотя вообще я допускаю, что break _до_ continue в теле одного и того же цикла могут создать помехи читателю, но такая ситуация должна встречаться редко.
Как я понимаю вся эта муть поднялась после того, как Вирт сделал Паскаль и Дийкстра написал "goto considered harmful". Как это обычно бывает с религиями, нормальные люди нашли и аппроприировали полезное зерно, ненормальные продолжают аппелировать к избранным местам Писания, написанного в совсем другую эпоху.
Для начала, goto considered harmful было написано когда в бейсике if something goto label было _единственным_ возможным способом использования if statement. Предложение сделать if something begin ... end и использовать это как можно чаще было крайне уместным, немедленно пустило корни во всех языках программирования, и теперь люди которые впитали с молоком матери языки где так можно неправильно интерпретируют оригинальный посыл, который был что такая возможность должна быть и будет уместна почти всегда, а как то, что надо всегда делать так. Потому что читают этот текст как если бы эта возможность уже есть, и следовательно он призывает неиспользовать goto не вместо структурного if, а вообще.
Далее, где-то там между Дийкстрой и Виртом была идея Структурного Программирования, которую они, заценив как заебически оно работает для большинства случаев, попытались продвинуть до full retarded, типа, чтобы любой кусок кода ограниченный begin...end можно было бы скопипейстить в любое другое место. Это, блджад, не работает и не может работать (как минимум потому что локальные переменные и у нас есть гораздо лучшие способы делать reusable code, выделяя его в referentially transparent функции например, где все зависимости должны быть явными. Типа, это была клёвая идея но оказалось что она не работает и есть другие идеи которые работают и гораздо лучше.
Но нет, люди опять и опять находят старые посты Дийкстры и Вирта, вменяемые идеи из которых уже есть во всех языках программирования, и смотрят на идеи которые время продемонстрировало как невменяемые (но это естественно не отражено в оригинальных постах и пытаются их использовать потому что блджад Авторитет. Или они услышали через третьи руки что нельзя использовать goto, break, continue, return.
Уродливы не сами операторы. Уродливо их используют. И даже если запретить goto/break/continue, всё равно быдлокодер найдёт способ написать плохо.
При этом талантливый разработчик напишет понятно и с goto.
приведи, пожалуйста, примеры красивого кода с goto, которые не сводятся к return/break/continue с меткой цикла.
Ядро Linux — это красивый код (тут считает до трёх и успокаивается я уже считал , что в среднем 5 штук goto на файл сорца в Linux, безотносительно «сведе́ния» о котором ты говоришь, так как оно, возможно, испортит прекрасный код, так что читай сорцы ядра.
приведи, пожалуйста, примеры красивого кода с goto, которые не сводятся к return/break/continue с меткой цикла.иногда это короче и читается лучше
while (I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS){
if (I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) == SUCCESS) goto end;
};
...
end:
vs
FlagStatus af=RESET;
while (I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS && af == RESET){
af = I2C_GetFlagStatus(I2C1, I2C_FLAG_AF);
};
if (af == RESET){
...
}
приведи, пожалуйста, примеры красивого кода с gotoобработка ошибок и откат предыдущих действий
err = do_foo;
if (err)
goto err_foo;
err = do_bar;
if (err)
goto err_bar;
err = do_baz;
if (err)
goto err_baz;
erturn 0;
err_baz:
undo_bar;
err_bar:
undo_foo;
err_foo:
return err;
приведи, пожалуйста, примеры красивого кода с goto, которые не сводятся к машине Тьюринга
В сях нет нетривиальных деструкторов, не говоря уже о dynamic-wind.
Поэтому если у тебя в начале функции открывается файл, а из нее десять разных точек выхода, логично вместо return там написать goto close_file_and_return;.
(Допустим на секунду, что десять разных точек выхода это хорошо.)
Использование объектов в качестве замены with-something-done
это тот ещё прикол.
> Поэтому если у тебя в начале функции открывается файл, а из нее
> десять разных точек выхода
И здесь мы опять возвращаемся к Дейкстре, Вирту и оправданию
использования "goto" через отсутствие вменяемых конструктов.
---
"А я обучался азбуке с вывесок,
листая страницы железа и жести."
обработка ошибок и откат предыдущих действийследующий код, имхо, понятнее выглядит - в явном виде имея записанный паттерн transaction. (далее псевдокод).
transaction_context trans;
trans=>do_foo =>undo_foo;
trans=>do_bar =>undo_bar;
do_baz;
trans.commit;
но в C++, c#/java, python уже достаточно высокоуровневых идиом, которые делают код понятнее, чем goto
err = do_foo;При структурном программировании отловит, у тебя нет.
if (err)
goto err_foo;
do_bar;
if (err)
goto err_bar;
err = do_baz;
if (err)
goto err_baz;
erturn 0;
err_baz:
undo_bar;
err_bar:
undo_foo;
err_foo:
return err;
далее псевдокодпиши на существующем языке, а то ты потом начнешь правила языка додумывать
> которые делают код понятнее, чем goto
Ни в плюсах, ни в яве, ни в питоне устранение хвостовых вызовов не то,
чтобы не гарантируется, оно принципиально не делается. Из-за этого
принципиально невозможно реализовывать автоматы вменяемым способом.
В питоне, кстати, это проявляется сильнее всего, так как сама
реализация медленная.
---
"Мы диалектику учили не по Гегелю.
Бряцанием боёв она врывалась в стих..."
в данном случае использовались идиомы:
- ошибка, как исключение
- очистка ресурсов по выходу из блока
- лямбда выражение
это всё есть в c# 3.5 и c++ 11. в python-е и в java-е не помню есть ли идиома "очистка ресурсов по выходу из блока"
Ни в плюсах, ни в яве, ни в питоне устранение хвостовых вызововя до сих пор считаю, что сведение к рекурсии более худшая идиома (в плане предсказуемости чем идиома конвейерной обработки последовательностей и деревьев.
соответственно, отсутствие устранения хвостовых вызовов - не критично.
ни в яветы гонишь. в яве хвостовая рекурсия конвертится в цикл, так написано, и я сам проверил
Иди подучи русский язык, может быть, узнаешь, чем вызов
отличается от рекурсии.
> я сам проверил
int f(int n) {if (n != 0) return g(n-1); else return 0;};
int g(int n) {if (n != 0) return f(n-1); else return 0;};
Иди, проверяй.
---
"Vyroba umelych lidi, slecno, je tovarni tajemstvi."
И да, я проверял основательно, на разных примерах и твой для меня не новость. Оптимизация хвостовой рекурсии явы в теории и на практике работает только для прямой рекурсии, то есть осуществляемой в пределах одного метода. В теории ещё долго будет работать именно так, потому как более общая оптимизация несовместима с механизмом безопасности jvm
> идиома (в плане предсказуемости чем идиома конвейерной
> обработки последовательностей и деревьев.
Да ты много чего считаешь, мы это уже давно знаем.
> соответственно, отсутствие устранения хвостовых вызовов - не критично.
Когда человек под автоматизацией производства понимает перекладывание бумажек,
то ему и устранение хвостовых вызовов не нужно.
---
"Дебилы, несмотря на замедленность и конкретность мышления,
низкий уровень суждений, узкий кругозор, бедный запас слов
и слабую память, способны к приобретению некоторых знаний
и профессиональных навыков."
зачем тебе понадобилась рекурсия для управления шаговым двигателем?
невозможно реализовывать автоматы вменяемым способом
с примером кода было бы лучше
Тем и отличается.
> И да, я проверял основательно, на разных примерах и твой для
> меня не новость. Оптимизация хвостовой рекурсии явы в теории
> и на практике работает только для прямой рекурсии, то есть
> осуществляемой в пределах одного метода. В теории ещё долго
> будет работать именно так, потому как более общая оптимизация
> несовместима с механизмом безопасности jvm
Не знаю насчёт "механизма безопасности," а на практике
отсутствие такой банальной оптимизации (которая совсем не
оптимизация) приводит к тому, что какие-нибудь тупые конечные
автоматы (с памятью или без) приходится переписывать через
специально придуманные обходные идиомы, приводящие к медленнее
работающему коду, так как на каждом шаге создаётся и уничтожается
куча стековых фреймов. В питоне, например, накладные расходы
могут быть вообще заоблачными, наподобие 30% времени, как у нас
получалось на одном прототипе.
---
"Мы диалектику учили не по Гегелю.
Бряцанием боёв она врывалась в стих..."
Вопрос: компилятор отловит вот такую ошибку?зависит от компилятора и опций. sparse отловит.
зависит от компилятора и опций. sparse отловит.И какую ошибку выдаст компилятор?
Дело в том, что код правильный, он просто делает другое. Компилятор не может запретить делать другое.
Насколько имеет смысл объяснять, зачем писать "(void) snprintf(...)",
человеку, опирающемуся на средства, которые выполняют преобразования кода,
обоснования корректности которых неизвестны?
---
"Vyroba umelych lidi, slecno, je tovarni tajemstvi."
ты, наверное, пошутил, но я нихера не понял. Твой батхерт по поводу использования современных инструментов, да, чувствуется.
а контра доказывает, сурово доказывает
(с)
как обычно, подпёздываешь?
Функции песочницы явы явно важнее такой элементарной оптимизации, как хвостовая рекурсия. Потому как в наборе микробенчмарков победил тот, в котором алгоритм был переписан в императивном стиле. Просто и банально таблица состояний. Так что без оптмизиации хвостовой рекурсии жить можно и хорошо
оно принципиально не делается.Оно не то чтобы принципиально не делается, оно подставляется компилятором где возможно. Не говоря о том, что можно самому сделать хвостовые вызовы, если понимаешь, что при этом изменяется время жизни объекта.
Можешь привести ссылку, какие именно функции имеются в виду?
Я ни разу пока ещё не встречал случая, когда какие-то мифические
функции оказывались важнее таких элементарных оптимизаций,
как развёртывание тела функции и устранение хвостового вызова,
а вот обратное, когда из-за идиотского ограничения языка
приходилось переписывать код в совершенно нечитаемые таблицы
переходов, встречал не раз.
---
"Прогресс науки обратно пропорционален числу выходящих журналов."
Можешь привести ссылку, какие именно функции имеются в виду?http://www.javaworld.com/javaworld/jw-05-1997/jw-05-security...
Реальные примеры влом искать, но дофига случаев когда если нужно сделать три или более if ...: continue, которые иначе превращались бы во вложенность утыкающуюся в правый край экрана. Мне по нраву плоский код. При этом вроде без понта пытаться их на функции разносить, потому что логически одна хрень, и проще её понять читая подряд, а не прыгая к определениям функций которым и вменяемые имена-то не дашь.
приведи, пожалуйста, примеры красивого кода с goto, которые не сводятся к return/break/continue с меткой цикла.
Алсо, я не верю в наивную парадигму структурного программирования что типа если б там этих continue/break/return не было, то ты бы всё сразу понял посмотрев на заголовок цикла, не читая его тело. Щаз.
transaction_context trans;
trans=>do_foo =>undo_foo;
trans=>do_bar =>undo_bar;
do_baz;
trans.commit;
То есть типа do_foo обломалось но мы всё равно делаем do_bar и do_baz? Замечательно. Ещё чуть-чуть и ты придумаешь как это завернуть в монаду!
То есть типа do_foo обломалось но мы всё равно делаем do_bar и do_baz? Замечательно. Ещё чуть-чуть и ты придумаешь как это завернуть в монаду!перед монадами тебе стоит вспомнить про исключения
Чота как-то дофига магеи, не?
transaction_context отвечает за хранение и добавление rollback-функций, если успешно выполнилась основная функция, и откат всех предыдущих ролбаков, если выполнилась не успешно
псевдокод TransactionContext следующий:
class TransactionContext
{
List<Action> rollbacks = new List<Action>
public void operator (Action do, Action undo)
{
try
{
do;
rollbacks.Add(undo);
}
catch
{
UndoAll;
throw;
}
}
public void commit
{
rollbacks.Clear;
}
public ~TranscationContext
{
UndoAll;
}
public void UndoAll
{
foreach (var undo in rollbacks.Reverse
undo;
rollbacks.Clear;
}
}
а на практикеотсутствие такой банальной оптимизации (которая совсем неоптимизация) приводит к тому, что какие-нибудь тупые конечныеавтоматы (с памятью или без) приходится переписывать черезспециально придуманные обходные идиомы, приводящие к медленнееработающему коду, так как на каждом шаге создаётся и уничтожаетсякуча стековых фреймов. В питоне, например, накладные расходымогут быть вообще заоблачными, наподобие 30% времени, как у насполучалось на одном прототипе.Это потому, что ты плохой программист, бро!
Описание конечного автомата должно быть декларативным, реифицированным как бы. Чтобы потом ты мог например мог пройтись по нему и посмотреть все ли возможные случаи описаны, а то и соптимизить его как-нибудь. И только потом ты его должен компилить в исполняемый код. Описание — отдельно, компиляция — отдельно. Помимо прочего отдельная компиляция позволит тебе скомпилить его дико эффективно, хоть прямо в питоновский байткод, хоть в С.
Это, кстати, дико яркий пример лиспа головного мозга, между прочим! Помнится, когда я зырил на курс Норвига про дизайн программ на Udacity меня именно это дико напрягло: вот он такой, зацените как клёво можно наш парсер перехуячить чтобы каждая штука возвращала лямбду, и даже вфигачить какую-то незначительную оптимизацию в процессе, что-то там шарится между разными лямбдами!
Не надо так делать, бро. Парсинг/декларации и компиляция должны быть отдельными шагами. Организовывать змеиную свадьбу из нереифицированной компиляции понатыканной промеж парсинга (и потом жаловаться что всё тормозит на Insufficiently Clever Evaluator) это как бы тупик прогресса, и вообще тупик и тупняк. То, что ты так можешь, не означает, что так нужно делать.
@: ну да, я и говорю, какая-то стрёмная неочевидная магея, мне дико не по нраву. Ты это уже использовал в продакшене? И коворкеры тебя не отпиздили за это?
@: ну да, я и говорю, какая-то стрёмная неочевидная магея, мне дико не по нраву. Ты это уже использовал в продакшене? И коворкеры тебя не отпиздили за это?и где магия?
это же просто стандартная реализация стандартного паттерна распределенной транзакции. и именно она и была в исходном примере.
ps
а ты как бы написал тоже самое?
Стрёмность магеи в том, что если ты между вызовами что-то сделаешь, то оно не отревертится.
То есть я бы понял если бы это всё выглядело как
execute_transactionally(params ActionAndRollback[] actions), ну, сразу видно что функция может делать что-то нетривиальное, и довольно тяжело напортачить, чисто синтаксически. А у тебя оно как бы делает вид что ты можешь делать всё, что позволяется языком, между вызовами твоей штуки. А на самом деле — нет!
ps
опыт показывает, что все эти предупреждающие названия болезнь переходного периода, когда разработчик еще не освоился с мощным инструментом и хочет всё вокруг обвесить предупреждающими флажками
Суть не в том, что функция называется execute_transactionally, а в том, что тебе будет тяжело незаметно для себя вставить туда нетранзакционированные действия. Потому что она получает массив action/rollback. И сразу видно что всё это является своего рода DSL.
Твой же код выглядит как обычный C#, и "освоение с мощным инструментом" состоит в том, что разработчик должен откуда-то узнать, что если он попытается сделать что-нибудь обычно-сишарповое между вызовами, типа вместо твоего
trans=>do_foo =>undo_foo;
trans=>do_bar =>undo_bar;
do_baz;
написать
trans=>do_foo =>undo_foo;
do_baz;
trans=>do_bar =>undo_bar;
то всё скомпилится отлично, но он получит неотлавливаемый баг в рантайме (потому что обычно-то транзакция не роллбэкается, а баг будет только тогда, когда случится ошибка в дико конкретном месте).
Я бы такие грабли перед собой не расстилал. И с немудрыми людьми которые считают себя достаточно умными чтобы их обходить, не работал бы.
edit: и кстати мой вариант-то более кратким получится, если что. По крайней мере пока все действия независимы, а когда они становятся зависимыми — нафигачь монаду же, благо даже няшный синтаксис для них в языке есть.
например, в коде ниже условие и цикл не участвуют в транзакции
if (условие)
trans=>do_foo =>undo_foo;
for(var i = 0; i < 10; ++i)
trans=>do_bar(i =>undo_bar(i;
do_baz;
и переписывание его через предложенную тобой идиому его лучше не делает
var actions = new List<TransactionAction>
if (условие)
actions.Add=>do_foo =>undo_foo;
for(var i = 0; i < 10; ++i)
actions.Add=>do_bar(i =>undo_bar(i;
actions.Add=>do_baz =>{});
execute_transactionally(actions);
что самое интересное твоя идиома никак не спасает от всё той же самой ошибки
execute_transactionally
(
new taction=>do_foo =>undo_foo
new taction=>{do_baz;do_foo}, =>undo_foo
)
do_baz здесь ровно так же не откатывается. и нафига тогда такое изменение?
А ты всё-таки найди.
> но дофига случаев когда если нужно сделать три или более
> if ...: continue, которые иначе превращались бы во вложенность
> утыкающуюся в правый край экрана.
И я расскажу тебе, как писать так, чтобы не утыкаться в правый край.
---
"Vyroba umelych lidi, slecno, je tovarni tajemstvi."
> реифицированным как бы.
Реифицированным как что?
У хороших программистов автомат уже реифицирован как набор функций
по одной на состояние.
> Чтобы потом ты мог например мог пройтись по нему и посмотреть
> все ли возможные случаи описаны,
Если у тебя каждому состоянию соответствует функция,
то пропустить её определение довольно сложно.
> а то и соптимизить его как-нибудь.
Соптимизировать что? Удалить недостижимые состояния?
Свернуть цепочку переходов в один даже туповатый компилятор может сделать,
правда, не в питоне, да.
> И только потом ты его должен компилить в исполняемый код.
Опыт показывает, что это на такое неоправданное усложнение жизни
приходится только из-за того, что существуют такие туповатые языки,
как питон и ява.
> Парсинг/декларации и компиляция должны быть отдельными шагами.
Осталось убедить коллег, что они должны использовать генератор
конечных автоматов (и потом прикручивать к нему память, а то и стек
а не изобретать странное.
> и потом жаловаться что всё тормозит на Insufficiently Clever Evaluator
Устранение хвостового вызова это настолько тупая оптимизация,
что она не выполняется только какими-то очень уж тупыми оптимизаторами.
Кстати, а если генератор КА туповат, то на что жаловаться?
---
"Мы диалектику учили не по Гегелю.
Бряцанием боёв она врывалась в стих..."
лиспа головного мозгау тебя кажись DSL головного мозга.
....
обычно-сишарповое ....
Нет такого понятия "обычно-сишарповое".
использовать генераторя ж говорю у человека DSL головного мозга, свой язычок на каждый случай
конечных автоматов
Иметь DSL это не плохо, проблема совершенно в другом:
очень часто все эти языки неоправданно ограничены
и несовместимы друг с другом.
Например, потребности растут, и внезапно из автомата Мили,
который уже не автомат Мили, а просто что-то очень похожее,
надо сделать что-то ещё сложнее.
---
"Вот тут как раз и начинается кино,
И подливает в это блюдо остроты
Белова Танечка, глядящая в окно,---
Внутрирайонный гений чистой красоты."
очень часто все эти языки неоправданно ограниченыименно про это я и говорю.
и несовместимы друг с другом
Иметь ограниченные, несовместимые DSL-и не плохо?
А ты всё-таки найди.Я тебе приведу код очень быстро сишный.
int do_spherical_action_in_space(int a, int b)
{
void* p = malloc(a);
if (!p) return -1;
if (ERR1) goto ret;
if (ERR2) goto ret;
if (ERR3) goto ret;
...
return XXX;
ret:
free(p);
...что-то ещё...
return -1;
}
Собственно, в плюсах это бы хорошо заменилось наличием деструктора у переменной, а вот в сях тебе надо все ресурсы освободить аккуратно, если что-то пошло не так.
Так как условий много, то даже банально один free (плюс скобочки {}) дадут увеличение числа строк.
Короче, читай код хорошо написанных штук, а не высказывания из интернетов, вырванные из контекста.
а вот в сях тебе надоа есть пример, который не связан с
Т.е. хочется пример, который ни на одном из существующих языков нельзя хорошо переписать без goto.
а есть пример, который не связан с недостатками конкретного языка?Это не недостаток языка! Более того, ЛЮБУЮ конструкцию с goto можно переписать и сделать без goto.
Т.е. хочется пример, который ни на одном из существующих языков нельзя хорошо переписать без goto.
Непонятно другое — откуда ненависть к goto? Си — это ассемблер, и операторы группы JMP — нормальное явление.
Пойми, что проблема не в goto. Проблема в том, что чтобы его умело использовать, надо 3-4 года опыта, чтобы уже языком в совершенстве владеть.
Ок, я готов заменить слово "недостатками" на "особенностями". Можешь на тот вопрос ответить после такой правки?
это ассемблеру структурного программирования и у ассемблера разные цели. Зачем их противопоставлять?
Можешь на тот вопрос ответить после такой правки?Любой код можно записать только используя if один.
Вообще, в тех же плюсах всякие деструкторы появились именно чтобы этот целый пласт случаев необходимости goto убрать.
Если ты заметил, goto используется в сишном коде и почти никогда в плюсовом.
int do_spherical_action_in_space(void* p, int b) {Кэп
if (!p) return -1;
if (ERR1) return -1;
if (ERR2) return -1;
if (ERR3) return -1;
... return XXX;
}
void* p = malloc(a);
int r = do_spherical_action_in_space(p);
free(p);
Возьми несклько действий: проверить наличие файла, узнать размер, что-то хитрое выделить, потом посчитать, потом опять новое уже выделить, ещё чо-то сделать. И на любом этапе всё завернуть с ошибкой.
Возьми несклько действий: проверить наличие файла, узнать размер, что-то хитрое выделить, потом посчитать, потом опять новое уже выделить, ещё чо-то сделать. И на любом этапе всё завернуть с ошибкой.Описываешь типичный Try-Catch-Finally, который на if-ах будет выглядеть лучше goto хотябы из-за того, что области жизни ресурсов будут показаны отступами во внутренних блоках.
Описываешь типичный Try-Catch-Finally, который на if-ах будет выглядеть лучше goto хотябы из-за того, что области жизни ресурсов будут показаны отступами во внутренних блоках.Ну try/catch и есть такая вот замена goto (что за finally? мы о плюсах же)
Не забываем только, что try/catch — это дорогое удовольствие. заменять хороший быстрый код с goto на исключения — это терять производительность. для узкого места, где обломы происходят стабильно — хреновая идея.
если поймалось то выполняет роллбэк функцию (только эту, или все предыдущие? Дико неявно их запоминая?)Почему неявно-то? Можно же функцию и кидать.
И какую ошибку выдаст компилятор?код неправильный. совсем.
Дело в том, что код правильный, он просто делает другое. Компилятор не может запретить делать другое.
В ядре на функции лепят атрибут __must_check (warn_unused_result) и ловят -Wunused-result
следующий код, имхо, понятнее выглядит - в явном виде имея записанный паттерн transaction. (далее псевдокод).кому как. на таком тривиальном примере возможно и понятнее. но всё равно уродливо.
лучше уж налепить объекты реализующие операции транзакции чем городить это уродство.
другой метод это реализовывать 'undo' операции безопасными на случай если 'do' не был позван.
типа free который прекрасно работает для NULL. тогда на unwind можно звать полноценный деструктор.
В ядре на функции лепят атрибут __must_check (warn_unused_result) и ловят -Wunused-resultя тут еще раз посмотрел на твой код. Моя претензия была связана с использование mutable переменной err. Но твой код с goto можно переписать и без mutable переменной:
int err_result;
{
var err = do_foo;
if (err) {
err_result = err;
goto err_foo;
}
}
{
var err = do_bar;
if (err) {
err_result = err;
goto err_bar;
}
}
{
var err = do_baz;
if (err) {
err_result = err;
goto err_baz;
}
}
return 0;
err_baz:
undo_bar;
err_bar:
undo_foo;
err_foo:
return err_result;
В таком виде goto вполне хорош. Спасибо за хороший пример c goto.
bool Method1
{
{
var err = do_foo;
if (err) {
err_foo;
return err;
}
}
{
var err = do_bar;
if (err) {
err_bar;
return err;
}
}
{
var err = do_baz;
if (err) {
err_baz;
return err;
}
}
return false;
}
void err_baz
{
undo_bar;
err_bar;
}
void err_bar
{
undo_foo;
err_foo;
}
void err_foo
{
//no-op
}
Using break and continue is not allowed in any of your code for this class. Using these statements damages the readability of your code. Readability is a quality necessary for easy code maintenance.Херня какая то. Не обращай внимание. Сколько людей столько и предпочтении. Для меня лично принцып break, continue вполне читабелен. В Google Python coding standard подобного ограничения нету.
Чем плох такой код и как его правильно написать, чтобы он отвечал современным стандартам?это явно не питоношный код
Главное выучи Google Python Coding Standard и используй утилиту pylint.py.
Первое это всегобщепризнанный стандарт а второе это соответсвующяя утилита для проверки соответствующего стиля, и поиска ошибок.
Оставить комментарий
maxiim9
Наткнулся на обсуждение Python Coding Standards Spring 13 университета Мэрилэндhttp://www.csee.umbc.edu/courses/201/spring13/standards.shtm...
Так вот пункт break & continue не даёт мне покоя:
Using break and continue is not allowed in any of your code for this class. Using these statements damages the readability of your code. Readability is a quality necessary for easy code maintenance.
Это же не в силу каких-то особенностей питона, правда ведь?
Например, есть два массива condArr и valArr одинаковой длины LEN.
Ищем в массиве valArr индекс первого элемента, равного некоторой константе CONST, при неком условии на второй массив. Чем плох такой код и как его правильно написать, чтобы он отвечал современным стандартам?