Pull to refresh

Comments 39

Забавный факт, но в c# и в c++ до сих пор в 2025 году есть оператор goto

Главное, чтобы он поддерживался компилятором.

Да, поддерживается.

Спасибо, те, с которыми я имел дело, все поддерживали, но, возможно, есть и такие, которые не поддерживают. Оператор перехода goto встречался мне в довольно профессиональных проектах.

В исходном коде Qt 5 я насчитал 2007 случаев использования goto

проблемы?

Без него простая логика превращается в нечитаемую лапшу. Например, возврат из многократно вложеного цикла, при обходе N-мерного массива. Или очистка тучи полей после malloc(), если в какой-то момент что-то пошло не так - иначе у нас будет копипаст блока кода для очистки ресурсов N раз. В ядре linux очень хорошо видны правильные примеры применения goto...

Боль - это когда его используют в высокоуровневом коде как jmp в ассемблере, заменяя нормальные управляющие конструкции языка.

Он есть даже в языке go, который создан относительно недавно.

Goto прекрасно используется везде, где его использование оправдано. Во внутреннем коде дотнета его использования достаточно много.

Злоупотребление goto в языках высокого уровня это симптом плохого кода. Принципиальное его отрицание - сектантство vulgaris.

Хороший компилятор все распедаливает как надо. Не сцать.

старательное избегание goto приводит к такому:

while (true) {
...

if (....) break;

....

break;
}

// попадаем сюда

Так последний абзац статьи ровно об этом

Дийкстра очень любил такие глобальные заявления. Потом кто-то (Уэзерелл?) ссылался на вот такое, ругая код отвалившегося (слава богу до старта) Апполона, что goto перерыгнул код аварийного останова.

У него же (?) или у Кнута была доп. концепция сопоставимого масштаба, что ошибка цикла должна вызывать его бесконечное исполнение, во избежание прыжка в запрещенные области.

Срач по этим темам был жуткий и длился лет 10.

Готу в 25 году? Реали? Когда только начинал кодить 20 лет назад уже говорили что готу это плохо. Да и вообще его не убирают только из обратной совместимости, по моему, хотя надо бы уже давно.

Для кода бизнес-логики плохо, а для стейт машин (таких как в async await) и оптимизации циклов (и не только циклов), клинапа во внутреннем коде - хорошо.

В языке REXX, которому "сто" лет, Go To нет изначально. Правда есть оператор SIGNAL, который может иметь смысл Go To, но основное назначение SIGNAL не для этого, а для обработки исключительных ситуаций. Например SIGNAL SYNTAX <label>, или SIGNAL ERROR <label>.

Давайте теперь рассмотрим операторы повторения (например, while B repeat A или repeat A until B). С логической точки зрения такие операторы излишни, поскольку повторение можно выразить с помощью рекурсивных процедур.

ужасно интересно посмотреть как эти очень сложные конструкции переписать через простую рекурсию.

Возможно это неудачный перевод. Надо смотреть оригинал.

P.S. Может это процедура, которая может вызывать саму сяба при определенных условиях выполнения. Но это тогда есть скрытый "оператора повторения".

Покажите любой код, я вам расскажу, как его переписать через рекурсию.

быстрое преобразование Фурье (БПФ), прям интересно!

Но вообще то это тоже код:

while B repeat A

но рассказывать не надо, надо переписать через рекурсию, начинать надо с самого простого, с фундаментального.

Какое слово вам лично оказалось непонятно в слове «код»?

    for (i = 0; i < 3; i++) //цикл по 3м точкам в строке 
    {
        if (col[x]) // проверяем флаг для текущего столбца
        {
            x += inc[level];
            continue;
        }

        if (level == 27) // для последней строки инкрементируем счетчик решений
        {
            count++;
            break;
        }

        col[x] = 1; // устанавливаем флаг
        line(level + 1); // запускаем поиск для следующей строки
        col[x] = 0; // сбрасываем флаг
        x += inc[level]; //переходим к следующему элементу
    }

вот здесь можете посмотреть в контексте, там есть и рекурсия, но без цикла как-то не обошлось. Можно заменить цикл на рекурсию тоже?

На псевдоязыке, синтаксис си у меня в RAM стёрся. Функция возвращает кортеж (col, count).

λ iter(n, &col, x, count, inc, level) {
  if (n >= 3) { return (col, count); }
  if (col[x]) { return iter(n - 1, col, count, x + inc[level], level); }
  if (level == 27) { return (col, ++count); }

  col[x] = 1;
  line(level + 1);
  col[x] = 0;
  x += inc[level];
  return iter(n - 1, col, count, inc, level);
}

спасибо за ответ. Мне всегда интересен взгляд со стороны. Но мне привычнее классическая запись, тем более что на Си это просто не скомпилируется, так писать нельзя и это меня вполне устраивает. Хотя на Си всегда можно было сохранять, передавать, отложено вызывать функции и построить на этом сколь угодно сложную логику. Поэтому зачем изобретать свой синтаксис мне не особо понятно. Прежде чем изобретать что-то свое надо бы освоить то что люди давно придумали и применяют десятилетиями, мне кажется.

Я не могу держать в памяти все 20 с лишним языков, на которых профессионально писал код.

Я ничего не изобретал — это псевдокод. Перевести его на С — вопрос пяти секунд, если помнить синтаксис. Я могу прямо сейчас его за те же пять секунд перевести на те языки, с которыми активно работаю в настоящее время: на эрланг, эликсир, раст, идрис, руби. Надо?

на эти языки нет стандартов, поэтому код на них это всегда лотерея с пониманием. Поэтому смысла нет.

потом я же в общем понял что вы написали, я просто не вижу смысла так писать. Вы считаете что в таком стиле код выглядит лучше - ваше право! Но вы же не занимаетесь анализом эффективности сгенерированного машинного кода, насколько я понимаю, так как пишите на интерпретируемых языках. У нас с вами разные области применения кода разрабатываемого. Наверно я не в курсе какой-то вашей специфики, также как вы не в курсе какой-то моей специфики работы.

Вы считаете что в таком стиле код выглядит лучше

Это еще почему? Я всего лишь сказал, что не существует кода, который невозможно реализовать на рекурсии. ПРо лучше/хуже — это ваши фантазии.

на эти языки нет стандартов

пишите на интерпретируемых языках

Уровень вашего кругозора понятен. Из перечисленных языков — интерпретируемый (да и то, с оговорками) — только руби.

вы же не занимаетесь анализом эффективности сгенерированного машинного кода

Это диагноз по аватарке, или что?

получается что я ошибся в своих предположениях. Извините.

Мы можем добавлять условные конструкции (if B then A), альтернативные (if B then A1 else A2),

If ...Then ... Else ... тоже еще та засада когда в предложениях Then и/или Else снова появляются IF. Это бомба. Читать такие конструкции сложно. Кроме написавшего никто не сножит охватить всей логики таких вложений.

Альтернативой явлется конструкция (аналог упоминавшегося в статье case):

Select

When <condition> <statement| block DO>

When <condition> <statement| block DO>

....

Otherwise <condition> <statement| block DO>

End /* Select*/

Давайте теперь рассмотрим операторы повторения (например, while B repeat A или repeat A until B). С логической точки зрения такие операторы излишни, поскольку повторение можно выразить с помощью рекурсивных процедур.

Никогда не имел проблем с операторами "повторения" (цикла обычно говорят программисты). Но есть много разных форм этих опереторов в разных языках и порой не очень удачных. Например For в языке С. С оператором DO в REXX у меня не было никаикх проблем. Этот опреатор может быть с индексной переменной или без нее, с WHILE/UNTIL и даже FOREVER (уравновешенный оператором LEAVE в теле цикла). А еще там есть оператор ITERATE досрочно завершающий цикл.

для примера, вот это:

int* foo(int bar)
{
    int* return_value = NULL;

    if (!do_something(bar)) {
        goto error_didnt_sth;
    }
    if (!init_stuff(bar)) {
        goto error_bad_init;
    }
    if (!prepare_stuff(bar)) {
        goto error_bad_prep;
    }
    return_value = do_the_thing(bar);

error_bad_prep:
    clean_stuff();
error_bad_init:
    destroy_stuff();
error_didnt_sth:
    undo_something();

    return return_value;
}

не лучше и не хуже чем вот это:

int* foo(int bar)
{
    int* return_value = NULL;

    if (do_something(bar)) {
      if (init_stuff(bar)) {
        if (prepare_stuff(bar)) {
          return_value = do_the_thing(bar);

        }
        clean_stuff();
      }
      destroy_stuff();
    }
    undo_something();

    return return_value;
}

но по объективным показателям, количество строк и/или количество знаков (особенно без учета white spaces), количество лексических единиц второй вариант, очевидно, маленько короче. Но субъективно для кого-то лучше воспринимается первый вариант, для кого-то второй. То есть это просто дело привычки и, наверно, индивидуальных особенностей восприятия разных видов форматирования текста, во основном.

В общем все сводится к общеизвестной формуле: "На вкус и цвет ...выбирайте правильное продолжение...", как говорится.

ЗЫ: ну еще в первом варианте есть одна, мало для кого очевидная, проблема, связанная с возможностью более безопасной модификации-расширения этого куска кода впоследствии. Но кто же в наше время об этом думает! Как-то исподволь все пришло к тому что за программистами должен подчищать компилятор всегда и везде.

Вот еще короче.

int* foo(int bar)
{
    return do_something(bar)
      && (init_stuff(bar)
        && (repare_stuff(bar)
            && do_the_thing(bar)
            || (clean_stuff() && NULL))
        || (destroy_stuff() && NULL))
      || undo_something() && NULL
}

Каждый пишет как он хочет.

Не исспользую гото, но если у меня его отберут, то буду крайне недоволен. И буду рассматривать возможность не исспользовать этот язык

Go to...

Ну собственно можно обойтись и без него.

Но когда пислал на ассемблере, то на ассемблере нет цикла, есть только переход.

Т.е. все циклы исключительно на базе переходов и сделаны.

Go to плох в отладке огромного полотна кода.

Использую goto в catch когда надо изменить какой то параметр и прогнать часть кода заново. Хз какие проблемы. .net 10 если что

Вспомнилась история (почему-то не гуглится), как в исходниках Win нашли то ли метку. то ли функцию с названием типа НеМогуПоверитьНоЯИспользовалЗапрещенныйОператор (на английском разумеется).

Sign up to leave a comment.

Articles