Здравствуйте, Khimik, Вы писали:
K>Извиняюсь если мой вопрос совсем ламерский, или если баян. Где-то я читал, что операторы безусловного перехода goto хорошему программисту не нужны, их надо заменять на стандартные блоки. Последние 9 лет я действительно обходился без goto, но недавно возникла задача, в которой обойтись без этого оператора было бы весьма неудобно (нужно перейти в более раннюю часть кода изнутри блока begin..end. Чтобы обойтись без goto, можно было бы поставить блок while…end; (и где-то внутри него continue, но с goto получилось явно изящнее. После этого у меня создалось ощущение, что в сложных алгоритмах оператор goto всё-таки приходится иногда применять, без этого не обойтись. Я прав?
Я воспитан на goto, потому что начинал на Фортране-4, а в нем не было цикла while. Поэтому методика написания этого цикла была : пишем как будто он выполняется 1 раз, потом условие с goto назад.
Тем не менее, уйдя с Фортрана, я применять goto прекратил. В последние лет 20 я его не написал ни разу.
Теоретически — все, что можно написать с goto, можно написать и без него. И не будет это хуже по эффективности, как бы кто ни заявлял.
Тем не менее я противник фанатизма, в т.ч. и goto-фанатизма. Заявлять, что категорически писать goto нельзя, я не буду. Тем более, что надо еще принять во внимание возможности того или иного языка (речь не о Фортране -4), насколько хорошо в нем реализованы замены. Например, я Яве выпутаться из кратных циклов можно достаточно элегантно, поставив break label, а в C++ — гораздо менее элегантно.
В общем, если использование goto делает код проще и понятнее — почему бы и нет ? Только сначала убедитесь, что иначе не получится.
Здравствуйте, WolfHound, Вы писали:
WH>>>Осталось, чтобы и ты это понял. V>>Ваша аргументация своей правоты меня восхищает. WH> Ну ты код то покажи.
Если вы по подробным инструкциям не способны сами написать код, то дискутировать с вами о преимуществах того или иного подхода считаю излишним.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Теоретически — все, что можно написать с goto, можно написать и без него. И не будет это хуже по эффективности, как бы кто ни заявлял.
Это будет хуже по эффективности.
Откройте какой мало-мальски критичный к производительности проект,
например тотже Фреймворк для дотнет и посмотрите сколько там гоуту ...
Здравствуйте, WolfHound, Вы писали:
ARK>>Обойтись без goto можно всегда. Есть люди, которые считают, что иногда goto делает код проще/лучше. Лично я считаю, что это не так. По моему мнению, если goto делает код проще, то это плохой код. WH>Удачи переписать без goto. Производительность пострадать не должна.
Я бы сделал КА на switch'е. Без дополнительных функций.
Не то, чтобы я не любил goto, но легко допустить ошибку когда-нибудь потом, при расширении функциональности.
_____________________
С уважением,
Stanislav V. Zudin
Здравствуйте, Khimik!
K>Извиняюсь если мой вопрос совсем ламерский, или если баян. Где-то я читал, что операторы безусловного перехода goto хорошему программисту не нужны...
Здравствуйте, Khimik, Вы писали:
K>Извиняюсь если мой вопрос совсем ламерский, или если баян. Где-то я читал, что операторы безусловного перехода goto хорошему программисту не нужны, их надо заменять на стандартные блоки.
Я использую goto на всех языках, на которых я пишу. И не капли не комплексую по этому поводу.
И вообще, какой-то у тебя староватый комплекс. Сейчас народ комплексует по поводу шаблонов и функциональщины.
Здравствуйте, BoobenCom, Вы писали:
BC>Это будет хуже по эффективности. BC>Откройте какой мало-мальски критичный к производительности проект, BC>например тотже Фреймворк для дотнет и посмотрите сколько там гоуту ...
Хуже с goto или без ? Если без goto — пример, пожалуйста.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, WolfHound, Вы писали:
WH>>Удачи переписать без goto. Производительность пострадать не должна.
К>На оптимизирующий компилятор закладываться можно? Или предполагается, что это всего лишь ассемблер с красивым синтаксисом?
Неужели сейчас кого-то волнует производительность?
Причём такая, которую может сломать goto?
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, BoobenCom, Вы писали:
BC>>Это будет хуже по эффективности. BC>>Откройте какой мало-мальски критичный к производительности проект, BC>>например тотже Фреймворк для дотнет и посмотрите сколько там гоуту ...
PD>Хуже с goto или без ? Если без goto — пример, пожалуйста.
Здравствуйте, Patalog, Вы писали:
ARK>>И рассуждение само по себе странное. У вас все программы из одной функции состоят? А то вдруг производительность того, просядет.
P>Оно странное только для того, кто никогда не занимался оптимизацией.
Обоснование?
(А то можно и наоборот: "оно не странное только для того, кто не писал ничего, кроме говнокода".)
K>После этого у меня создалось ощущение, что в сложных алгоритмах оператор goto всё-таки приходится иногда применять, без этого не обойтись.
Поздравляю! Вы перешли на новый уровень в понимании Дао программирования.
Здравствуйте, WolfHound, Вы писали:
К>>Самое простое с т.з. рефакторинга в данном случае — написать три локальные функции, и вместо goto new_better делать return new_better(). Полагая, что компилятор их проинлайнит. WH>Но что это даст? Чем оно принципиально отличается от goto кроме того что там нет слова goto?
Это радикально улучшает читабельность, потому что return видно сразу.
Здравствуйте, WolfHound, Вы писали:
К>>Самое простое с т.з. рефакторинга в данном случае — написать три локальные функции, и вместо goto new_better делать return new_better(). Полагая, что компилятор их проинлайнит. WH>Но что это даст? Чем оно принципиально отличается от goto кроме того что там нет слова goto?
Это упростит трассировку покрытия кода и позволит компилятору провести какую-нибудь более мощную оптимизацию — например, проинлайнить твою функцию Append() или вывести для неё граничные условия. А так — компилятор увидел, что внутри спагетти, ну и бросил это гиблое дело.
WH>Но можно пойти ещё дальше. Есть верование, что функция должна иметь ровно один выход. Чтобы соответствовать ему придётся вообще прыгать вокруг флагов.
Или прыгать вокруг ветвящихся выражений — тернарного оператора, свитчей, паттерн-матчинга.
В функциональных языках это очень даже естественно.
Кстати, функцию ведь можно декомпозировать и наоборот: отделить диагностику от исполнения
А вот в языках с ручным управлением ресурсами (Си, бейсик там всякий) — один выход — это борьба за чистоту рук. Ведь перед выходом надо выполнить код освобождения локальных ресурсов. Чем больше выходов, тем больше копипасты.
К>>Либо понадеяться, что компилятор способен трассировать булевы флаги. WH>Тут я вообще не понял, что ты предлагаешь.
Вот что я предлагаю.
enum Decision { NotSet | ChooseNew | ChooseOld | Ambiguity };
public Append() : void
{
assert3(newResult > 0);
// флаг для трассировкиmutable decision = Decision.NotSet;
//очищаем флаги
parseResult.rawTree[newResult] = parseResult.rawTree[newResult] & ExtensibleRuleParser.RawTreeMask.Id;
parseResult.rawTree[newResult + ExtensibleRuleParser.RawTreeOfs.Next] = lastResult;
lastResult = newResult;
// сдаётся мне, твой код when / if / else / else / when можно было написать более причёсанно,
// но не хочу вдаваться в логику и просто оберну два стейтмента - каждое в свою обёрткуwhen (decision == Decision.NotSet)
when (bestResult <= 0) decision = Decision.ChooseNew;
when (decision == Decision.NotSet)
{
if (bestEndPos < 0) if (newEndPos >= 0) decision = Decision.ChooseNew; else decision = Decision.Ambiguity;
else when (newEndPos < 0) decision = Decision.ChooseOld;
}
// двойная обёртка - только ради того, что здесь появились локальные переменные
// (кстати, компилятор С++ надавал бы по рукам за прыжки goto поверх переменных - потому что деструктор же!)
// отрефакторить легко: надо вместо def сделать mutable и выполнить единственное присваивание под обёрткой.when (decision == Decision.NotSet)
{
def newTokens = parseResult.TokenEnumerator1.Start(newResult, curTextPos);
def bestTokens = parseResult.TokenEnumerator2.Start(bestResult, curTextPos);
while (decision == Decision.NotSet)
{
def newSize = newTokens.NextTokenSize();
def bestSize = bestTokens.NextTokenSize();
if (newSize > bestSize) decision = Decision.ChooseNew; else
if (newSize < bestSize) decision = Decision.ChooseOld; else
when (newSize < 0) decision = Decision.Ambiguity;
}
}
// в этом месте мы можем поклясться, что решение принято.
// хотя из goto это следовало лишь трассировкой покрытия кода (по способам выпрыгнуть из while true)
// флаг позволяет добавить нам чуть больше отладочности!
assert (decision != Decision.NotSet);
// либо внести изменения в алгоритм, чтобы тот допускал дефолтные случаи (например, если вообще не входить в цикл)when (decision == Decision.NotSet) decision = ?????; // вот что-то такое сделать
// здесь надо бы написать match(decision) ..., но для единообразия продолжу на when.when (decision == Decision.Ambiguity) //АСТ равен лучшему. Неоднозначность.
{
parseResult.rawTree[newResult] = parseResult.rawTree[newResult] | ExtensibleRuleParser.RawTreeFlags.Equal;
assert(bestEndPos == newEndPos);
}
when (decision == Decision.ChooseNew) //Новый АСТ лучше
{
bestEndPos = newEndPos;
bestResult = newResult;
parseResult.rawTree[newResult] = parseResult.rawTree[newResult] | ExtensibleRuleParser.RawTreeFlags.Best;
}
when (decision == Decision.ChooseOld) //Старый АСТ лучше
{
}
// нахаляву получили единственный return void.
}
Код стал страшнее и многословнее. Зато он стал линейным. Для некоторых платформ это одно удовольствие.
Только я хочу подчеркнуть: я не РЕЗКО ПРОТИВ goto.
Если по каким-то причинам (говнокомпилятор) чем меньше вызовов функций и лишних флагов, тем лучше, — то пожалуйста.
Хоть всю программу запихай в одну мега-кастрюлю со спагетти.
хъ
ARK>>>И рассуждение само по себе странное. У вас все программы из одной функции состоят? А то вдруг производительность того, просядет.
P>>Оно странное только для того, кто никогда не занимался оптимизацией.
ARK>Обоснование?
Чего? Что инлайн приводит к увеличению исполняемого кода? Тебе это не очевидно? Или не очевидно, что этот увеличившийся объем может не влезть в кэш? Или что если нагруженная ф-я не влазит в кэш то страдает перфоманс?
ARK>(А то можно и наоборот: "оно не странное только для того, кто не писал ничего, кроме говнокода".)
Я про твой говнокод ничего не говорил, не надо мне свои фантазии приписывать.
Здравствуйте, Stanislav V. Zudin, Вы писали:
SVZ>Здравствуйте, WolfHound, Вы писали:
ARK>>>Обойтись без goto можно всегда. Есть люди, которые считают, что иногда goto делает код проще/лучше. Лично я считаю, что это не так. По моему мнению, если goto делает код проще, то это плохой код. WH>>Удачи переписать без goto. Производительность пострадать не должна.
SVZ>Я бы сделал КА на switch'е. Без дополнительных функций. SVZ>Не то, чтобы я не любил goto, но легко допустить ошибку когда-нибудь потом, при расширении функциональности.
Любой goto можно переписать в свитч, но это добавит ещё как минимум один переход и ещё одно сравнение. Ну и, если честно, в настоящем виде код читается не так уж плохо.
Здравствуйте, Patalog, Вы писали:
P>Чего? Что инлайн приводит к увеличению исполняемого кода? Тебе это не очевидно? Или не очевидно, что этот увеличившийся объем может не влезть в кэш? Или что если нагруженная ф-я не влазит в кэш то страдает перфоманс?
Из ложной посылки — и все остальное тоже ложь.
ARK>>(А то можно и наоборот: "оно не странное только для того, кто не писал ничего, кроме говнокода".) P>Я про твой говнокод ничего не говорил, не надо мне свои фантазии приписывать.
Пока что поток фантазий идет только с вашей стороны.
хъ
P>>Чего? Что инлайн приводит к увеличению исполняемого кода? Тебе это не очевидно? Или не очевидно, что этот увеличившийся объем может не влезть в кэш? Или что если нагруженная ф-я не влазит в кэш то страдает перфоманс?
ARK>Что инлайн приводит к увеличению исполняемого кода — нет, не очевидно. И не только мне: http://rsdn.ru/forum/philosophy/6025071
К сожалению, ты не асилил даже прочитать до конца сообщение на которое ссылаешься — "И начиная с определённого порога, такой вариант станет медленней "классического" подхода, как минимум потому что будет забиваться instruction cache". Хотя да, поскольку ты только погавкаться — тебе это не нужно.
Здравствуйте, Patalog, Вы писали:
ARK>>Что инлайн приводит к увеличению исполняемого кода — нет, не очевидно. И не только мне: http://rsdn.ru/forum/philosophy/6025071
P>К сожалению, ты не асилил даже прочитать до конца сообщение на которое ссылаешься — "И начиная с определённого порога, такой вариант станет медленней "классического" подхода, как минимум потому что будет забиваться instruction cache".
Хм. Причем тут это?
Вот эта ваша фраза, гражданин оптимизатор — "инлайн приводит к увеличению исполняемого кода" — ложь. И выводы из нее, соответственно, тоже.
В каких-то случаях приводит, в каких-то не приводит.
P>Хотя да, поскольку ты только погавкаться — тебе это не нужно.
У меня нет цели ни с кем "гавкаться". С этим обратитесь к зеркалу.
Если желаете конструктивного диалога, то не стоит начинать разговор с наезда.