Форум программистов, компьютерный форум, киберфорум
Наши страницы
Etyuhibosecyu
Войти
Регистрация
Восстановить пароль
Рейтинг: 3.67. Голосов: 3.

Goto. Левая демагогия, правая демагогия и факты (информация к размышлению)

Запись от Etyuhibosecyu размещена 03.06.2019 в 09:32
Обновил(-а) ildwine 05.06.2019 в 21:33

Вступление.
Когда-то в низкоуровневых языках программирования было всего четыре группы операторов: арифметические, адресация, ввод/вывод и переходы. Арифметические - это канонические четыре арифметических действия: сложение, вычитание, умножение и деление, которые, как правило, встречались в двух вариантах: целом и с плавающей точкой. Адресация - это занесение данных в память и считывание их из памяти - со временем она обрела абстракцию в виде имеющих имена переменных. Ввод/вывод - это название говорит само за себя: ввод с клавиатуры, обработка нажатий мыши, прослушивание микрофона - и вывод на перфоленту, в консоль, на экран, на принтер и т. д. Остается четвертая группа - переходы. Она самая маленькая - всего два оператора: условный переход и безусловный переход, причем условный включает в себя безусловный. Условный переход позже обрел абстракцию в виде оператора if, причем внутри этого оператора стали выполняться не переходы, а непосредственные действия. Но если с модернизацией условного перехода еще кое-как, то безусловный переход превратился в миллион абстракций: continue, break, вызов функций, return и т. д. А началось все с того, что какой-то никому не известный Дейкстра написал статью против goto, став основателем стуктурного программирования. НО!!! Современные пользователи отвергают и goto, и структурное программирование, хотя как это можно совмещать - нормальному человеку никак не понять...
В настоящем вступлении написаны большей частью факты, оспаривать которые - равнозначно, что оспаривать, что человеку (за исключением единичных недоказанных аномалий) необходимы еда и сон. А теперь перейдем к основной части.
Правая демагогия.
Goto ухудшает читабельность кода. Goto опасен и провоцирует возникновение трудноуловимых ошибок. Goto - плохо и некрасиво.
Левая демагогия.
С точностью до наоборот, goto очень часто улучшает читабельность кода. Программировать конечные автоматы без goto практически невозможно. Создатели Java не модернизировали оператор break, а урезали и переименовали оператор goto.
Факты.
Соль улучшает суп? (Больных редкими аномальными заболеваниями и прочие ничтожные меньшинства прошу не брать в расчет.) Без соли невкусно, правда? А если на суп для семьи из трех человек положить полпачки соли? Также и с goto в высокоуровневых языках. То, что все хорошо в меру, если только вы не желаете войти в книгу рекордов Гиннесса - это факт. Goto в меру и там, где надо - улучшает читабельность кода. Не в меру - ухудшает. По поводу опасности - нож опасен? 220 вольт опасны? Но 99.999% нормальных людей в нормальных странах ими пользуются. И в программировании, например, приведение типов крайне опасно. А такой код: #define if(a) if(a && rand() % 25) - вставьте его в какую-нибудь давно отлаженную функцию, в которую никто не смотрит, так как все знают, что в ней нет ошибок - и оружие давления на боссов готово! Относительно "плохо и некрасиво" - на вкус и на цвет товарища нет, и это тоже факт! Автоматы я пытался программировать, но быстро сдался, так что ничего сказать не могу. По поводу создателей Java - спорить об этом тем, кто как минимум не общался хоть с кем-то из сотрудников компании Java - лишено смысла.
Правая демагогия.
Глядя на участок кода с меткой в начале, уже невозможно сказать, сколькими путями и откуда мы сюда попадем.
Левая демагогия.
В эпоху goto программировать мог каждый. Предложение превышало спрос, и команда теоретиков программирования под руководством Дейкстры решила "исправить" ситуацию - сделать, чтобы программировать было труднее и программистам платили больше. Goto дает программисту большую свободу, а у власть имущих смысл жизни подрезать человечеству крылья.
Факты.
Теоретически доказано, что не существует кода с goto, который нельзя без потери функциональности переписать без goto. А вот эффективность теряется почти гарантированно, и это тоже факт. И то, что все виды while, for, switch, return и т. д. компилятор преобразует в goto - тоже факт, но его почему-то принято замалчивать... По поводу правой точки зрения - я пользуюсь Visual Studio, в которой есть команда "найти все ссылки", которая как раз и указывает, сколькими путями и откуда код обращается к любому идентификатору, в том числе и к метке. По поводу свободы - чрезмерная свобода приводит к беззаконию. В случае с goto - к Синему Экрану Смерти, а то и поломке аппаратного обеспечения. Лично я ни одного такого идиота не знаю, который бы уничтожил свой компьютер с помощью goto, но включение математической логики делает это видным в глаза. И что программировать мог прямо "каждый" - я не верю.
Правая демагогия.
Goto внутрь цикла или функции - почти гарантированные серьезные баги в программе.
Левая демагогия.
Выйти без goto из вложенных циклов - дикое извращение, флаги забивают память и отнимают время.
Факты.
Ни то, ни другое не противоречит фактам. Но также не противоречит фактам то, что любой нормальный компилятор запрещает goto внутрь цикла или функции, а вот наружу - не запрещает, если только в языке вообще есть этот оператор.
Заключение.
Я не придерживаюсь ни одной из радикальных точек зрения - ни левой, ни правой. Считаю, что goto через строку в высокоуровневых языках - плохо, но - следующее слово является ключевым - ИНОГДА - он не помешает. И вообще я считаю, что не только goto, а каждым действием, возможным в каждой ситуации, необходимо пользоваться с умом. А также, что ни во что где-либо написанное не нужно верить до уровня фанатизма. Независимо от того, это статья Дейкстры о программировании, Библия или труды Карла Маркса о материализме.
Также приведу решение задачи из одного из соседних блогов:
Цитата:
Сообщение от нтч Просмотреть комментарий
Условие: дано 9 чисел: 47, 88, 22, 86, 94, 83, 97, 62, 27
Требуется найти те числа, которые в сумме дадут число 300
Если решений несколько, то распечатать все решения
Более того, я даже усложню эту задачу: не 9 заранее известных чисел, а произвольное количество введенных из консоли. Сколько циклов будет в таком случае? Как вложенных, так и одного уровня? Я не проверял свой код компилятором и не гарантирую его корректность относительно неявных приведений типов и прочих ошибок, исправить которые не составит никакого труда. Главное - уловить суть. Также не привожу способ вывода вектора, написать его - тривиальная задача.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <iostream>
#include <vector>
 
int main() {
    int n = 0;
    std::vector<int> values = std::vector<int>();
    std::cout << "Enter n:" << std::endl;
    std::cin >> n;
    if (n <= 0) {
        std::cout << "Invalid input!";
        return 0;
    }
    for (int i = 0; i <= n - 1; i++) {
        std::cout << "Enter values["  << i << "]" << std::endl;
        std::cin >> values[i];
    }
    int pos = 0;
    std::vector<int> pos_vector = std::vector<int>();
    int pos2 = -1;
    int sum = 0;
less:
    pos_vector.push_back(pos);
    sum += values[pos];
    pos++;
    pos2++;
    goto selection;
greater:
    if (pos2 <= 0) goto less;
    sum -= values[pos_vector[pos2 - 1]];
    pos_vector.erase(pos_vector.begin() + pos2 - 1, pos_vector.begin() + pos2);
    pos2--;
    goto selection;
equal:
    output_result(values, pos_vector);
    if (pos >= n) goto end_reached;
    goto greater;
end_reached:
    if (pos2 <= 0) goto exit;
    sum -= values[pos_vector[pos2]];
    pos_vector.pop_back();
    pos2--;
    sum += values[pos_vector[pos2] + 1] - values[pos_vector[pos2]];
    pos_vector[pos2]++;
    pos = pos_vector[pos2] + 1;
    goto selection;
selection:
    if (sum == 300) goto equal;
    if (pos >= n) goto end_reached;
    if (sum > 300) goto greater;
    goto less;
exit:
    system("pause");
    return 0;
}
Возможно, код немного непривычный, но если натренироваться, понять, когда куда прыгаем, можно. Возможно, тут есть ошибки, повторяю, компилятором я не проверял. Но факт то, что у меня ОДИН уровень вложенности блоков вместо ВОСЕМНАДЦАТИ. Думаю, что кардинально переписать этот код нельзя, можно только так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
enum State {}
...
    State state;
    while (true) {
        if (state == less) {
            ...
            if (...) {
                state = greater;
                continue;
            }
            ...
            if (...) {
                state = end_reached;
                continue;
            }
        }
        if (state == greater) {
            ...
        }
        ...
        if (state == end_reached) {
            ...
        }
        ...
    }
Но такое изменение сути дела не меняет, по сути это те же самые goto. Кто может возразить? Еще раз повторю, я не являюсь ярым борцом ни за левую, ни за правую точку зрения. Я - посередине между ними.
Размещено в Без категории
Просмотров 395 Комментарии 21
Всего комментариев 21
Комментарии
  1. Старый комментарий
    Аватар для Rius
    OMG, ещё один иксперд подтянулся...
    Запись от Rius размещена 03.06.2019 в 10:25 Rius на форуме
  2. Старый комментарий
    Программа не рабочая от слова вообще, и дело не в приведении типа, алгоритм сам неверный, не находит числа
    Запись от ТабуретY размещена 03.06.2019 в 10:43 ТабуретY вне форума
    Обновил(-а) ТабуретY 03.06.2019 в 10:50
  3. Старый комментарий
    Цитата:
    Сообщение от ТабуретY Просмотреть комментарий
    Программа не рабочая от слова вообще, и дело не в приведении типа
    Не верю. Я кое-как программировал на C++ почти полтора года.
    Запись от Etyuhibosecyu размещена 03.06.2019 в 10:49 Etyuhibosecyu вне форума
  4. Старый комментарий
    Возможно, нет функции output_result, но написать ее - тривиальная задача.
    Запись от Etyuhibosecyu размещена 03.06.2019 в 10:51 Etyuhibosecyu вне форума
  5. Старый комментарий
    Цитата:
    Сообщение от Etyuhibosecyu Просмотреть комментарий
    Возможно, нет функции output_result, но написать ее - тривиальная задача.
    Все такие ошибки я исправил, программа не находит числа
    Запись от ТабуретY размещена 03.06.2019 в 10:54 ТабуретY вне форума
  6. Старый комментарий
    Аватар для Usaga
    О боже мой... Снова заговоры, снова домыслы... Получается, что если в каждом втором предложении будет слово "факт" выделенное жирным, то весь текст становится неоспоримым?

    Цитата:
    hile, for, switch, return и т. д. компилятор преобразует в goto - тоже факт, но его почему-то принято замалчивать...
    Это не замалчивается. Предполагается, что это каждому дебилу и так ясно, а потому не требует упоминания.
    Запись от Usaga размещена 03.06.2019 в 10:55 Usaga вне форума
  7. Старый комментарий
    Аватар для bedvit
    Не рабочий код - это плохо. Создается впечатление, что автор к своей же теме, подходит несколько несерьезно. Что тогда можно по этой теме прокомментировать? Начать холивар по goto? Накинуть на вентилятор... Скучно...
    Запись от bedvit размещена 03.06.2019 в 11:06 bedvit на форуме
  8. Старый комментарий
    Надеюсь, такой код будет рабочим. На моем наборе работает.
    C++
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    
    #include <iostream>
    #include <vector>
     
    int main() {
        int n = 0;
        std::cout << "Enter n:" << std::endl;
        std::cin >> n;
        if (n <= 0) {
            std::cout << "Invalid input!";
            return 0;
        }
        std::vector<int> values = std::vector<int>(n);
        for (int i = 0; i <= n - 1; i++) {
            std::cout << "Enter values["  << i << "]" << std::endl;
            std::cin >> values[i];
        }
        int pos = 0;
        std::vector<int> pos_vector = std::vector<int>();
        int pos2 = -1;
        int sum = 0;
    less:
        pos_vector.push_back(pos);
        sum += values[pos];
        pos++;
        pos2++;
        goto selection;
    greater:
        if (pos2 <= 1) goto less;
        if (pos_vector[pos2] != pos_vector[pos2 - 1] + 1) goto less;
        sum -= values[pos_vector[pos2 - 1]];
        pos_vector.erase(pos_vector.begin() + pos2 - 1, pos_vector.begin() + pos2);
        pos2--;
        goto selection;
    equal:
        output_result(values, pos_vector);
        if (pos >= n) goto end_reached;
        goto greater;
    end_reached:
        if (pos2 <= 0) goto exit;
        sum -= values[pos_vector[pos2]];
        pos_vector.pop_back();
        pos2--;
        sum += values[pos_vector[pos2] + 1] - values[pos_vector[pos2]];
        pos_vector[pos2]++;
        pos = pos_vector[pos2] + 1;
        goto selection;
    selection:
        if (sum == 300) goto equal;
        if (pos >= n) goto end_reached;
        if (sum > 300) goto greater;
        goto less;
    exit:
        system("pause");
        return 0;
    }
    Простите за загрузку не на форум, но я не нашел, как добавить вложение в комментарий в блоге, вот скриншот.
    Запись от Etyuhibosecyu размещена 03.06.2019 в 11:31 Etyuhibosecyu вне форума
  9. Старый комментарий
    Упс... снова нерабочий. Лень отлаживать до конца, главное, что вы уловили суть - что написать такой код можно, прочитать при желании также можно (хотя, если честно, сам иногда путаюсь, но не в метках, а в самих действиях), и восемнадцати вложенных блоков нет. Хотя разводить холивар не вижу смысла, у меня была цель выложить демагогию обеих сторон и факты и получить один-два комментария. Уже получил больше, спасибо. Блог можно закрывать.
    Запись от Etyuhibosecyu размещена 03.06.2019 в 11:56 Etyuhibosecyu вне форума
  10. Старый комментарий
    Аватар для Usaga
    Прочитать-то можно, а вот нормально понять уже сложно, ибо надо проследить всю цепочку "прыжков" по меткам.

    Показать-то что хотели этим кодом? Что используя goto можно написать код? Так это и так известно было. Что читабельность падает показать хотели?
    Запись от Usaga размещена 03.06.2019 в 12:00 Usaga вне форума
  11. Старый комментарий
    Ну хорошо, а может кто-то написать без goto? Чисто теоретически интересно, сколько же там будет циклов?
    Запись от Etyuhibosecyu размещена 03.06.2019 в 12:13 Etyuhibosecyu вне форума
  12. Старый комментарий
    Ну, можно написать еще с рекурсией, только тогда в случае нескольких миллионов чисел можно рухнуть на StackOverflow...
    Запись от Etyuhibosecyu размещена 03.06.2019 в 12:17 Etyuhibosecyu вне форума
  13. Старый комментарий
    Аватар для Croessmah
    Цитата:
    Сообщение от Etyuhibosecyu Просмотреть комментарий
    Не верю. Я кое-как программировал на C++ почти полтора года.
    И что изменилось за это время? )
    Запись от Croessmah размещена 03.06.2019 в 13:20 Croessmah на форуме
  14. Старый комментарий
    Аватар для Croessmah
    Цитата:
    и т. д. компилятор преобразует в goto - тоже факт, но его почему-то принято замалчивать...
    Цитата:
    Это не замалчивается. Предполагается, что это каждому дебилу и так ясно, а потому не требует упоминания.
    Не верно. Все аппелируют к ассемблеру, но в асме вообще goto нет.
    Есть множество инструкций для прыжков (jmp, ja, je, jle, js, jns, ...)
    goto метка не обязана сразу приводить к jmp метка;.
    goto - это такая же языковая конструкция, как и все остальные. Она также подчиняется правилам языка.
    На примере C++ кода это хорошо видно: https://godbolt.org/z/m3PMh-

    Здесь goto done; превратился не в jmp done, а в jmp к концу блока с помещением в регистр ebx флага откуда был сделан переход, чтобы в дальнейшем уже оттуда прыгнуть в done, после вызова деструктора автоматического объекта.
    Цитата:
    и оружие давления на боссов готово!
    Это действует только на дураков. Конечно же, у идиотов боссы всегда дураки, да.
    Цитата:
    Goto внутрь цикла или функции - почти гарантированные серьезные баги в программе.
    Даже C не позволяет прыгать внутрь функций. Если речь про asm, то там нет функций, так же, как и goto.
    Запись от Croessmah размещена 04.06.2019 в 12:55 Croessmah на форуме
    Обновил(-а) Croessmah 04.06.2019 в 13:08
  15. Старый комментарий
    Аватар для bedvit
    Croessmah, вот это интересно. Спасибо за инфо.
    Запись от bedvit размещена 04.06.2019 в 19:55 bedvit на форуме
  16. Старый комментарий
    Цитата:
    Выйти без goto из вложенных циклов - дикое извращение, флаги забивают память и отнимают время.
    Зависит от ЯП.
    Выход из 4 циклов.
    PureBasic
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    While x<10
      For i=0 To 20
        For z = 2 To 100
          v=0
          Repeat
            v+1
            If x=8
              Break 4  ; Выход из циклов.
            EndIf
          Until v>100
        Next
      Next
      x+1
    Wend
    Запись от locm размещена 05.06.2019 в 12:45 locm вне форума
  17. Старый комментарий
    Аватар для CoderHuligan
    Цитата:
    Сообщение от locm Просмотреть комментарий
    Зависит от ЯП.
    Выход из 4 циклов.
    И чтобы понять где точка выхода придётся точно также искать конечный NEXT, к тому же ещё и считать в уме до четырёх))
    Запись от CoderHuligan размещена 05.06.2019 в 12:51 CoderHuligan на форуме
  18. Старый комментарий
    И что вы предлагаете в качестве альтернативы?
    Запись от locm размещена 05.06.2019 в 12:52 locm вне форума
  19. Старый комментарий
    Аватар для CoderHuligan
    Цитата:
    Сообщение от locm Просмотреть комментарий
    И что вы предлагаете в качестве альтернативы?
    То что предлагает ТС. Альтернатива всегда есть.
    Запись от CoderHuligan размещена 05.06.2019 в 14:44 CoderHuligan на форуме
  20. Старый комментарий
    Аватар для CoderHuligan
    Цитата:
    Сообщение от Croessmah Просмотреть комментарий
    Не верно. Все аппелируют к ассемблеру, но в асме вообще goto нет.
    Есть множество инструкций для прыжков (jmp, ja, je, jle, js, jns, ...)
    jmp - безусловный переход, как и goto.
    Запись от CoderHuligan размещена 05.06.2019 в 14:45 CoderHuligan на форуме
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru