LINUX.ORG.RU

COMEFROM считается вредным?

 


0

1

Когда Дейкстра написал своё письмо «Оператор GOTO считается вредным», в качестве шутки придумали ещё более вредный оператор COMEFROM (и ассемблерную инструкцию CMFRM). Он позволял указать метку и выполнять дополнительный код всегда, когда выполнение проходило через эту метку.

Но вот смотрю я на нынешние методологии программирования и вижу огромный пласт COMEFROM в SQL в виде CREATE TRIGGER, подписку на события в других языках (паттерн Наблюдатель). Многомерный COMEFROM в HTML через CSS.

Неужели это считается удобным для понимания и отладки?

★★★★★

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

Можно пример?

А так, я считаю, что все операторы нужны. А всяким «кастраторам» языков руки бы поотрывал.

Bad_ptr ★★★★★
()
Ответ на: комментарий от Bad_ptr

Можно пример?

Бейсик (с доп. оператором):

10 COMEFROM 40
20 INPUT "WHAT IS YOUR NAME? "; A$
30 PRINT "HELLO, "; A$
40 REM

Питон (реально компилируется):

from goto import comefrom, label

comefrom .repeat
name = raw_input('What is your name? ')
if name:
    print("Hello", name)
    label .repeat
print("Goodbye!")
monk ★★★★★
() автор топика
Последнее исправление: monk (всего исправлений: 1)

Вредность goto заключалась не в том, что он куда-то в другое место идёт, а в том, что флоу оттуда не возвращался. Какой-нибудь gosub в этом плане сильно менее вреден. Так и comefrom, в исходном предложенном виде оттуда тоже не возвращаются. А из хендлера события или из наблюдателя или ещё откуда возвращаются.

PolarFox ★★★★★
()
Ответ на: комментарий от PolarFox

А из хендлера события или из наблюдателя или ещё откуда возвращаются.

Не всегда. Бывает триггер на INSTEAD OF. Бывает, что обработчик события запускает совсем другую ветку программы.

monk ★★★★★
() автор топика
Ответ на: комментарий от PolarFox

exit обычно не сразу после цикла.

Рекомендуют цикл паковать в функцию и заменять goto на return.

monk ★★★★★
() автор топика

Твоё описание COMEFROM совершенно неадекватное. Прочтя первый раз я подумал «ну что за бредятина?». Потом начал читать комменты, увидел там твой пример, и всё встало на свои места. Да, твоё его описание формально можно считать правильным, но не надо так делать. Хотя мне лень придумывать нормальное описание, но мог бы хотя бы написать что-то типа «goto, объявленный в точке назначения, а не в точке откуда делается переход» - оно хоть и корявое но и то получше.

Теперь по остальному.

SQL

1) SQL - это не язык программирования, несмотря на то что некоторые извращенцы его пытаются использовать в такой роли, так что аналогия неверна

CREATE TRIGGER

2) CREATE TRIGGER - это не COMEFROM никаким боком, это хук, поэтому аналогия ещё раз не верна

нынешние методологии программирования

3) А вот в совсем даже не нынешнем фортране подобная практика - норма (смотри синтаксис оператора цикла с меткой на конце, один в один), и это не в шутку а серьёзно так делают

        do 1003 i=1,5
        print *,'i ='
1003    print *,i

И ответ на вопрос

COMEFROM считается вредным?

Да, я бы его считал вредным. Это какие-то отголоски декларативного программирования, встроенные в нормальный императивный код. Вместо него надо использовать GOTO, с ним всё в порядке, ну или структурные операторы.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 2)
Ответ на: комментарий от PolarFox

Вредность goto заключалась не в том, что он куда-то в другое место идёт, а в том, что флоу оттуда не возвращался.

Вредность goto (была) в том, что читая программу очень сложно понять, что именно она делает. Из тех же времён сравнение кода со спагетти. Надо было пройти по каждой ветке до конца, чтобы понять, что делает программа.

Сейчас современные версии COME FROM делают примерно то же самое. «INSERT VALUES 1 INTO T1» может сделать с базой что угодно (и даже все затронутые триггеры одним запросом не получить, надо вручную смотреть каждый insert/update/delete в коде триггера и порядок триггеров). Также как глядя на HTML даже с выключенным JS сейчас невозможно предсказать, что будет видно в браузере (даже текст!).

monk ★★★★★
() автор топика
Ответ на: комментарий от firkax
  1. SQL - это не язык программирования, несмотря на то что некоторые извращенцы его пытаются использовать в такой роли, так что аналогия неверна

Всё, на чём можно писать алгоритмы, является языком программирования. SQL даже тьюринг-полный.

  1. CREATE TRIGGER - это не COMEFROM никаким боком, это хук, поэтому аналогия ещё раз не верна

COMEFROM и есть хук. Или хук (как возможность позволяющая его воткнуть к любой строке кода) и есть COMEFROM. Мы где-то отдельно пишем «выполнять этот код всегда, когда встретится DELETE FROM T1». Это в чистом виде COMEFROM с возвратом.

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

Возможность писать алгоритмы, как и тьюринг-полнота не означает что этот инструмент предназначен для написания на нём программ. Язык программирования - это инструмент, сделанный специально для написания программ, а не инструмент, у которого такая возможность оказалась побочным образом. SQL это язык запросов, программы на нём писать не надо.

Хук это вызываемая при выполнении действия функция. COMEFROM - не функция, а переход (GOTO) и вызывается оно не по действию, а по достижению метки. Ещё по достижению метки вызываются брейкпоинты, они тоже не хуки. COMEFROM - и не брейкпоинт, по той же причине: и хук, и брейкпоинт подразумевают выполнение функции (и возврат управления назад откуда его временно взяли) а не перевод потока выполнения программы (хотя и хуком и брейкпоинтом можно и иногда начитерить перевод выполнения, но это не основная их функция). Возможно, все эти штуки со стороны кажутся похожими друг на друга, но не надо путать, это на самом деле совсем разное.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)

Сами они вредные, всё надо и гото надо. Ты пральна написал что это лицемерие, гото плохой, а каскадные таблицы стилей это модно молодёжно и наглядно ага, ага.

Да есть случаи когда goto как зайчик прыгает вверх, вниз, туда, сюда по 50 раз. Тяжело читать. Но можно и for,switch,if/else и прочими нагородить не менее не читаемую херобору.

Так что всё фигня, тут просто важно разделять, фанатиков и просто у кого претензии адресные к конкретному коду. А то увидит Алёнка два перехода goto на ошибку и сразу TRIGGGGGGERED HATE HATE HATE!!

И всё с ней понятно сразу, истеричка, дура, фанатичка.

Молодёжное реактивное программирование, та же херня только с боку, каскадные изменения всего и вся при изменении чего либо одного, работает то норм, но если отлаживать уууууууууууууууууу =)

Так что Дейкстра истеричка и критиковал он ЧЕРЕЗМЕРНОЕ использование goto когда на нём ваааще всю логику фигачили. Просто преподал в такой манере что теперь все нагло и без стыда врут везде что goto это плохо, не goto плохо, плохо когда goto в goto на goto под goto.

Забей, не парься и используй goto. Но в меру.

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от firkax

SQL это язык запросов, программы на нём писать не надо.

PL/SQL (на котором триггеры) уже не язык запросов.

и хук, и брейкпоинт подразумевают выполнение функции а не перевод потока выполнения

Если только этой функцией не является продолжение.

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

PL/SQL (на котором триггеры) уже не язык запросов.

SQL это язык запросов, все костыльные надстройки над ним его сути не меняют. А триггеры это вообще не фича языка а фича реализации сервера субд.

Если только этой функцией не является продолжение.

Ты написал какую-то чушь. Функция это что-то, что начинается с запоминания «куда вернуться» и возвращается по запомненному адресу после того, как она сделала свои задачи. За некоторыми исключениями, но речь не о них. В контексте данного определения твоя фраза - бессмыслица.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 2)
Ответ на: комментарий от LINUX-ORG-RU

Но можно и for,switch,if/else и прочими нагородить не менее не читаемую херобору.

Ага. Вот никакого goto:

n = (count + 7) / 8;
switch (count % 8) {
case 0: do { *to = *from++;
case 7:      *to = *from++;
case 6:      *to = *from++;
case 5:      *to = *from++;
case 4:      *to = *from++;
case 3:      *to = *from++;
case 2:      *to = *from++;
case 1:      *to = *from++;
        } while (--n > 0);
}
monk ★★★★★
() автор топика
Ответ на: комментарий от firkax

SQL это язык запросов, все костыльные надстройки над ним его сути не меняют. А триггеры это вообще не фича языка а фича реализации сервера субд.

Арифметика не позволяет описать алгоритм, все костыльные надстройки над ней её сути не меняют. А ввод-вывод это вообще не фича языка а фича реализации операционной системы. Вывод: Фортран и Си не языки программирования.

Функция это что-то, что начинается с запоминания «куда вернуться» и возвращается по запомненному адресу после того, как она сделала свои задачи.

Продолжения (там где они есть) имеют синтаксис функций. Кстати, также как в Си есть функции longjmp и exit. Они тоже не возвращаются по запомненному адресу.

monk ★★★★★
() автор топика
Ответ на: комментарий от hateyoufeel

Это ж duff’s device. Что в нём сложного?

Не все с первого раза понимают, как он должен работать.

Другой вопрос, что он тупо не работает с новыми компиляторами.

В смысле? Вроде компилируется и работает с GCC 12.

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

В смысле? Вроде компилируется и работает с GCC 12.

Я имею ввиду, профита от него никакого сейчас. Компиляторы сами loop unrolling без проблем делают. Duff’s device может только хуже сделать.

hateyoufeel ★★★★★
()
Последнее исправление: hateyoufeel (всего исправлений: 2)
Ответ на: комментарий от monk

case 0: do { *to = *from++;

case 1: *to = *from++;
} while (–n > 0);

Что так можно? Разбивать цикл между несколькими case. Получается что case – это тот же goto.

X512 ★★★★★
()
Последнее исправление: X512 (всего исправлений: 1)
Ответ на: комментарий от monk

Ты можешь различить штатное использование инструмента от костылей/побочек/исключений итд?

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

Основное назначение функции - получить управление, сделать что-то, и отдать его назад, туда же откуда оно получено. Да, есть всякие exit(), longjmp() или ещё разные способы сделать не так, но это - исключения. Основное назначение перехода (goto) - передать управление насовсем. Хотя и тут, конечно, есть исключения: с помощью goto вполне можно всякими доп. костылями реализовать логику вызова функции.

И так вот, COMEFROM это именно переход, а триггер в базе - вызов. COMEFROM делается по метке, триггер в базе - по действию. Совсем разные вещи.

firkax ★★★★★
()
Ответ на: комментарий от X512

Да, так и есть.

switch это синтаксический сахар для goto switchtable[value2index(value)] либо, если значения идут подряд - goto switchtable[value]

А case - метки.

Например можно так:

switch(x) {
case 1: y=4;
        if(z==5) {
case 2:   y++;
          break;
        }
        z++;
}

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от firkax

И так вот, COMEFROM это именно переход, а триггер в базе - вызов. COMEFROM делается по метке, триггер в базе - по действию. Совсем разные вещи.

Но они схожи. Ещё есть Excel там возврат действия назад нет. И вообще вся логика строится на двумерном COMEFROM (с ячейками вместо меток и COMEFROM на все ячейки, участвующие в формуле).

CSS3 (ладно, здесь COMEFROMANDRETURN) / React JS (здесь тоже чистый COMEFROM, так как выполнение возвращается не назад, а пользователю).

monk ★★★★★
() автор топика

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

это полезно, так собственно брикпоинты и работают. продолжайте наблюдение.

alysnix ★★★
()
Ответ на: комментарий от monk

а ещё в C/С++ на метки можно прыгать по указателю

sparks ★★★★
()
Ответ на: комментарий от monk

Ничего схожего. И аналогия с excel вообще полностью дурацкая, императивного кода в ячейках нет.

Мне кажется ты просто не понял суть оператора COMEFROM, придумал себе по мотивам его внешних признаков какой-то философский ярлык и теперь лепишь его без разбору на всё вокруг.

COMEFROM - это примерно то же самое, что GOTO (инструмент низкоуровневого структурирования кода одной функции), только сделанное задом наперёд и от этого крайне неудобное (впрочем, как я уже писал, фортран-программисты именно так писали циклы десятилетиями и им было удобно). Это никоим образом не хук и вообще не инструмент внешнего вмешательства в работу самодостаточного кода (хотя, как я уже выше писал, любой инструмент можно использовать каким-то извращённым способом совсем не по назначению).

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от alysnix

Ты тоже ввёлся в заблуждение его корявым описанием. Никакого «дополнительного» кода там нет, просто штатный переход на другую строку кода. Т.е. это не брейкпоинт, а извращённый вариант goto.

firkax ★★★★★
()
Ответ на: комментарий от firkax

Ничего схожего. И аналогия с excel вообще полностью дурацкая, императивного кода в ячейках нет.

Тот код, который выполняется при изменении ячейки вполне императивен. C COMEFROM перед выполнением кода в формуле ячейки. Причём с множественным. На одну ячейку будет несколько COMEFROM (от каждой зависимой ячейки), следующий выполняется после окончания программы, начатой в предыдущем.

monk ★★★★★
() автор топика
Ответ на: комментарий от PolarFox

Вредность goto заключалась не в том, что он куда-то в другое место идёт, а в том, что флоу оттуда не возвращался.

GOTO и GOSUB браковались потому, что при их активном использовании код превращался в менее читабельную лапшу.

saahriktu ★★★★★
()
Ответ на: комментарий от monk

Повторяю: ты неправильно понимаешь что такое COMEFROM. Это всего лишь странным образом записанный GOTO и ничего более. Никакие хуки, предрасчёты и что ты там ещё напридумывал тут совершенно ни при чём.

firkax ★★★★★
()

Правильно написали, вреден не сам GOTO, а его неумеренное использование.

И с другой стороны — да, 90% случаев, где GOTO оказывается полезен, более надёжно и наглядно записываются с помощью BREAK с меткой (если ЯП позволяет).

hobbit ★★★★★
()
Ответ на: комментарий от firkax

Никакие хуки, предрасчёты и что ты там ещё напридумывал тут совершенно ни при чём.

Так у меня и претензии не к практически не существующему COMEFROM (INTERCAL и первоапрельский модуль к питону не в счёт), а к реально существующей парадигме программирования, при которой практически невозможно определить что именно выполнится при действии пользователя просто глядя на текст программы.

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

Хорошо, но не надо COMEFROM к этому приплетать. Оно про другое. Его «непредсказуемость» примерно из той же серии как то, что «непонятно», какая операция будет следующей после закрывающей фигурной скобки («}») в конце for или while-цикла.

А те случаи, когда действительно непонятно, что выполнится в конкретной строчке, мне тоже не нравятся. Но почему-то в первую очередь не css вспоминается (хотя там такое, конечно, есть, но на мой взгляд не критично), а c++ с его перегрузками всего подряд. А вот excel всё так же считаю что тут ни при чём, это калькулятор для непрограммистов с другим подходом.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 3)

Неужели это считается удобным для понимания и отладки

Ты ещё исключения вспомни, которые тот же goto вид сбоку.

COMEFROM в SQL в виде CREATE TRIGGER, подписку на события в других языках (паттерн Наблюдатель)

Да, но там же изолированная логика, никак не связанная с основным потоком исполнения. Типа создаём пост и по этому событию кидаем уведомление. Отлаживается всё это разумеется отдельно. Более того это как раз удобно.

no-such-file ★★★★★
()
Ответ на: комментарий от PolarFox

что флоу оттуда не возвращался

Не то чтобы не возвращается, но возвращается ну туда, откуда вызвали. И более того, таких точек выхода может быть несколько.

из хендлера события или из наблюдателя или ещё откуда возвращаются

Нет, не возвращаются. Но это и не требуется, т.к. это обычно совершенно обособленный код. Он на основную логику никак не влияет. Т.о. вызывается он или не вызывается – для вызывающего кода безразлично.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

CREATE TRIGGER … Да, но там же изолированная логика, никак не связанная с основным потоком исполнения.

Да ну?

CREATE TRIGGER products_delete
ON Products
INSTEAD OF DELETE
AS
UPDATE Products
SET IsDeleted = 1
WHERE ID =(SELECT Id FROM deleted)
SELECT COUNT(*) FROM Products; // 42
DELETE FROM Products;
SELECT COUNT(*) FROM Products; // всё равно 42

Или не 42, если есть ещё один триггер на DELETE или UPDATE.

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

может сделать с базой что угодно

Да, но в контексте исполняемого оператора тебе не надо об это знать.

надо вручную смотреть каждый insert/update/delete в коде триггера и порядок триггеров

Ну знаешь, дай дураку стеклянный член… Если от конкретных триггеров, а тем более их порядка что-то зависит, то нужно увольнять тимлида/архитектора.

no-such-file ★★★★★
()
Ответ на: комментарий от monk

Да ну

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

no-such-file ★★★★★
()
Ответ на: комментарий от firkax

а c++ с его перегрузками всего подряд

У С++ просто считай каждый оператор именем функции с типами в этом имени, тогда неожиданностей нет.

хотя там такое, конечно, есть, но на мой взгляд не критично

Когда в тексте <HTML><BODY><P>Привет!</P><BODY></HTML> а на экране в браузере красный квадрат с зелёной надписью «Иди к чёрту!», это нормально?

А вот excel всё так же считаю что тут ни при чём, это калькулятор для непрограммистов с другим подходом.

На нём программы пишут. Как раз в стиле COMEFROM. Ввод в ячейки, цепочка формул подберёт ответ. И если ответ неправильный, то найти как он получается очень сложно, так как не видно, какие ячейки меняются при изменении ячейки ввода. Приходится идти по алгоритму задом наперёд.

Его «непредсказуемость» примерно из той же серии как то, что «непонятно», какая операция будет следующей после закрывающей фигурной скобки («}») в конце for или while-цикла.

for и while всегда локальны. А

f(x)
{
10: y = x + 1;
20: z = y * 2;
30: return z;
}

g(y)
{
40: if(y == 42) {
50:    comefrom 20
60: }
70: return 0;
}

Даёт неопределённость вызова f(69). Может быть 140, а может 0. Смотря с какими y вызывалась g.

monk ★★★★★
() автор топика
Последнее исправление: monk (всего исправлений: 2)
Ответ на: комментарий от no-such-file

Ага, например в ЛИСП.

Психологический возраст.

PolarFox ★★★★★
()
Ответ на: комментарий от monk

Нет, не даёт. И у тебя сразу две ошибки. Во-первых, этот код вообще некорректный, метка 20 из функции g не видна. Исправим это.

f(x, y)
{
10: y = x + 1;
20: z = y * 2;
30: return z;
40: if(y == 42) {
50:    comefrom 20
60: }
70: return 0;
}
Во-вторых, результат выполнения этой функции не зависит от y, потому что этот код эквивалентен (полностью, без исключений) такому:
f(x, y)
{
10: y = x + 1;
20: z = y * 2;
    goto 50;
30: return z;
40: if(y == 42) {
50:    ;
60: }
70: return 0;
}

for и while всегда локальны. А

В этом и есть видимо корень твоего заблуждения. COMEFROM так же локален. Повторю в пятый раз, это всего лишь задом наперёд записанный GOTO.

firkax ★★★★★
()
Ответ на: комментарий от no-such-file

Если от этого у тебя в вызывающем коде что-то зависит, то поздравляю – твой код говно.

Один человек пишет код: удалять старые записи, пока из общее количество больше 42. У него всё работает.

Другой человек пишет код: записи удалять не окончательно, а вместо этого ставить флаг. У первого человека программа перестаёт работать.

monk ★★★★★
() автор топика
Ответ на: комментарий от no-such-file

Если от конкретных триггеров, а тем более их порядка что-то зависит, то нужно увольнять тимлида/архитектора.

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

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

У С++ просто считай каждый оператор именем функции с типами в этом имени, тогда неожиданностей нет.

Я же не писал «операторов». Я писал «всего подряд». Выяснить, какая именно функция из кучи функций с одинаковым именем будет вызвана (и в каком файле она задана, и вообще часть ли проекта этот файл), не всегда просто. Отличаться функции могут как списком параметров, так и классом, чьими методами они являются, в т.ч. виртуальными и зависящими от неизвестно чего. А тип «auto» дополнительно усложняет трассировку программы, когда нужно выяснить, какой же там тип параметра по факту.

Когда в тексте <HTML><BODY><P>Привет!</P><BODY></HTML> а на экране в браузере красный квадрат с зелёной надписью «Иди к чёрту!», это нормально?

Это всё же не штатное использование CSS. При желании такие фокусы с любым языком можно сделать.

Ввод в ячейки, цепочка формул подберёт ответ

Это называется функциональное программирование, и оно ни при чём ни к COMEFROM, ни к «непонятно что вызывается», которые взаимно ни при чём друг к другу.

firkax ★★★★★
()
Ответ на: комментарий от firkax

Во-первых, этот код вообще некорректный, метка 20 из функции g не видна.

С чего это? Там где был COMEFROM метки были глобальны.

потому что этот код эквивалентен (полностью, без исключений)

Не эквивалентен. COMEFROM выполняется только если y==42, а у тебя безусловно.

monk ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.