Sbtrn. Devil
> Так по твоей парадигме parse_file тоже должен возвращать HRESULT.
Нет, в моей парадигме, хрезулт — это всего лишь способ просунуть фатальное условие через границу разных ABI. В рамках одной программы — ты просто ничего не делаешь и позволяешь эксепшонам самим автоматически всплывать по стеку.
Sbtrn. Devil
> Например, следом за распарсиванием кучки юнитов идёт qsort, в котором в качестве калбакса - компаратор с контролем консистентности
Это всё происходит локально внутри одной эксепшно-аллокаторной среды — поэтому просто кидаем птичку, и она летит.
Sbtrn. Devil
> затем запуск на выполнение пачки вычислений и reduce их результатов с опять-таки кастомным калбаксом (в случае первого же найденного фейлового результата редукцию и возможное выполнение оставшихся можно и нужно прерывать, но стандартный reduce такому не обучен)
Если это "подпрограмма не смогла выполнить поставленную задачу" — кидай птичку, и пусть она летит. А если это штатный ранний выход, например если посреди длинного умножения получился ноль — для этого нужен аналог reduce с официальной поддержкой штатного раннего выхода. А перематывать чужие кишки костылями задом наперёд — не надо.
Sbtrn. Devil
> но стандартный reduce такому не обучен
Ну всё, конец света, без точечных эксепшонов теперь нам эту проблему никак не решить.
Имбирная Ведьмочка
> В рамках одной программы — ты просто ничего не делаешь и позволяешь эксепшонам самим автоматически всплывать по стеку.
И в итоге на любую ошибку любого уровня (не прочитался файл, не удался с первого раза коннект, юзер кликнул за пределами окна, и т. д.) будет только один вариант реакции - уронить всё и вывалить стек. Может быть, с сохранением воркспейса (если юзеру повезёт).
> Ну всё, конец света, без точечных эксепшонов теперь нам эту проблему никак не решить.
Она без них и не решается.
> для этого нужен аналог reduce с официальной поддержкой штатного раннего выхода.
- как ты сам и заметил, затраты на решение примерно равны "выкинуть старую имплементацию под ноль и написать вместо неё новую".
Sbtrn. Devil
> И в итоге на любую ошибку любого уровня (не прочитался файл, не удался с первого раза коннект, юзер кликнул за пределами окна, и т. д.) будет только один вариант реакции - уронить всё и вывалить стек. Может быть, с сохранением воркспейса (если юзеру повезёт).
А какие ещё могут быть варианты? Ты смог придумать четвёртую кнопку помимо Аборт, Ретрай и Кенсел?
Sbtrn. Devil
> "выкинуть старую имплементацию под ноль и написать вместо неё новую"
Если для тебя написать с нуля interruptible_reduce — это проблема, то волшебные исключения — это явно не то, в чём ты нуждаешься прямо сейчас больше всего.
Имбирная Ведьмочка
> А какие ещё могут быть варианты? Ты смог придумать четвёртую кнопку помимо Аборт, Ретрай и Кенсел?
Какой-нибудь фотошоп или паинт-нет, например, показывает юзеру сообщение и продолжает работать, не покидая контекста текущей операции (например, клонирующая кисть). Они же не знают, что нужно падать кишками напоказ.
> Если для тебя написать с нуля interruptible_reduce — это проблема, то волшебные исключения — это явно не то, в чём ты нуждаешься прямо сейчас больше всего.
Если ты думаешь, что алгоритмы, которые придётся написывать с нуля, не могут быть сложнее reduce, то у тебя явное недопонимание размера проблемы.
Задумайся, кстати, над тем, почему во всех вменяемых языках, скрипя зубами, рано или поздно реализуют break/continue на произвольное число уровней - это практически та же самая проблема.
Прочитал в обосноваче на break/continue label такую причину нелюбви к goto:
goto is innately more difficult to use because to understand its purpose, the user has to know where the jump target is located. A goto past_the_loop behaves radically differently compared to a goto before_the_loop. Moving the jump target or the goto statement relative to each other can also completely change these semantics.
Но ведь тогда получается, что можно сделать goto_forward и goto_backward (разрешающие нахождение соответствующих меток только в соответствующей стороне), и эта причина исчезнет!
Sbtrn. Devil
> Но ведь тогда получается, что можно сделать goto_forward и goto_backward (разрешающие нахождение соответствующих меток только в соответствующей стороне), и эта причина исчезнет!
А можно просто дать метке говорящее имя. Дурака ты в любом случае не одолеешь, а недурак справится и с тем что уже есть и так.
Sbtrn. Devil
> Какой-нибудь фотошоп или паинт-нет, например, показывает юзеру сообщение и продолжает работать, не покидая контекста текущей операции (например, клонирующая кисть). Они же не знают, что нужно падать кишками напоказ.
try { currentTool->apply(currentLayer, currentView->ScreenToPixmap( currentMousePosition)); } except ( Exception const& e) { currentTool = MakeDefaultSelectionTool( ); PostShowErrorMessageBox( e); }
При этом выяснять, что именно пошло не так в currentTool->apply, на уровне программного кода необязательно.
Имбирная Ведьмочка
> При этом выяснять, что именно пошло не так в currentTool->apply, на уровне программного кода необязательно.
А если это "не так" - обнаружение коррупции текущего файла, при котором таки нужно именно падать, но только окном с текущим файлом? И, естественно, после возникновения такой поправки мы не хотим обмазывать дополнительным if (e.type == FILE_WIDE_FATAL_ERROR) каждый случай типа currentTool->apply.
Тут нам и помогает, если currentTool знает, куда ему кидать свои исключения, а его коллабораторы знают, куда кидать свои.
Задумался тут, по мотивам прошедших тем, над вопросом, как оценить читаемость кода.
Ключевая мысль: говнокод не тот, который занимает много места, а тот, в котором расшифровка символов требует больших затрат.
На этом основании можно предварительно измыслить метрику читаемости:
1. Каждый символ, употреблённый в каком-либо месте, добавляет сложность в количестве строк, отделяющих его от декларации, плюс число строк в самой декларации (за декларацию считаем минимально необходимое число строк, чтобы получить представление о символе и его возможностях в месте применения - скажем, число строк в публичном интерфейсе класса, или в декларации переменной). Если декларация находится в другом файле, то расстояние до декларации = число строк в этом другом файле * (1 + логарифм от числа файлов в проэкте). Если символ употребляется в оцениваемом юните несколько раз, то его сложность считается как среднее от всех употреблений в юните.
1.1. Символы одинакового написания, но обозначающие разные сущности (например, одноимённые локальные переменные в разных блоках), считаются как разные символы.
2. Сложность базовой конструкции языка, или какого-нибудь библиотечного выражения, считается как число занимаемых ей строк, умноженное на число разновидностей конструкций/выражений в юните. Для конструкций типа goto label/break/return итд. число строк считается как число строк между оператором и меткой, или между ним и макушкой зависимой конструкции. Если конструкция употребляется в оцениваемом юните несколько раз, то её сложность считается как среднее по всем употреблениям - но помним про множитель из числа конструкций. Т. е., скажем, если в юните используются for, if и while, то сложность, допустим, for - среднее число строк по всем for юнита, но также умноженное на 3.
Смысл в том, что разнообразие зоопарка конструкций, сымсл которых нельзя восстановить из кода и которые надо заранее знать, наказывается квадратичным ростом сложности.
3. Сложность юнита складывается из сложностей всех (различных) символов и конструкций, которые в нём употребляются, но эта сумма делится на число строк в юните. Смысл в том, что расшифровать символ нужно только один раз на юнит, поэтому усилия на расшифровку повторяющихся символов в длинном юните снижаются.
При подсчёте количества строк строки, превышающие 80 символов, можно считать за несколько (nLines = Math.ceil(numSymbols / 80)).
Sbtrn. Devil
Всё это летит к чертям в SQL-запросах.
Я не знаю как там в игровых движках, но в бизнесе и бухгалтерии SQL-запросы это АДОВЫЙ КРОМЕШНЫЙ АДИЩЕ ИЗ АДОВ.
Я как нибудь с рабочего места ради интереса могу запостить какой нибудь типовой запросик 1С ЗУП. Это жопа жопская из жопеней прежопенистых.
Видно как сама фирма 1С эволюционировала со временем в этом очень непростом деле.
Сперва в её движке были только вложенные запросы - запрос в запросе - это дико делинеаризивало код и было совсем мраком.
Потом они тотально начали отказываться от многоэтажных вложенных запросов и перешли почти на 90% на временные таблицы.
Это сильно линеаризовало код.
Второй очень сильны ход конём - аналог того что в классическом SQL называется представления/view.
Но 1С даже хитрее сделали - для удобства они представления синтезируют чисто программно кодом.
Тупо есть функция ЗаменитьПредставленияВТекстеЗапроса(ТекстЗапроса) которая просматривает текст запроса в поисках шаблонов подстановки представлений и анализирует его и заменяет на нечто иное. И это нечто иное может быть (и очень часто так и есть) под сотню других временных таблиц сливаемых и спрягаемых в один итог.
Идея в целом простая - мы знаем что у нас есть сотрудник и у него есть огромный массив разнородной информации о нём в сотнях разных таблиц - от ИНН и признака участника чернобыльской АЭС до графика работы на заданную дату или его состояния работы на заданную дату - так вот мы подготоваливаем временную таблицу с колонками (Дата, Сотрудник) с нужными нам колонками - запрашиваем нужные сведения - и код в функции ЗаменитьПредставленияВТекстеЗапроса проанализирует какие колонки нам нужны и создаст минимальный запрос к минимальному числу таблиц где содержаться нужные нам сведения. Что именно получится решается динамически исходя из того какие колонки мы из представления требуем. Это вот и отличает от классических View в лучшую сторону.
Функция ЗаменитьПредставленияВТекстеЗапроса в кишках своих это ООП-монстр который заповедует ООП-коллекций "источников данных" и опрашивает их на предмет колонок и делегирует им подстановку текстов запроса - довольно мощная подсистема, уважуха и респект.
Это реально ну просто маст-хев т.к. при переделке структуры таблиц не нужно переделывать все запросы обращающиеся к таблице.
Но всё-равно это ад когда половина логики приложения находится в небоскрёбных запросах.
Sbtrn. Devil
> При подсчёте количества строк строки, превышающие 80 символов, можно считать за несколько (nLines = Math.ceil(numSymbols / 80)).
видел образцы подсчёта, где читаются не строки, а операции.
т.е. записать всё в одну строку в 2000 символов
или расписать всё по отдельным строчкам - оценнаная сложность будет одинаковая.
но в целом "считать операции" более сложная оценка, чем считать строки.
Ведь для подсчёта операций требуется парсить код.
=A=L=X=
> Но всё-равно это ад когда половина логики приложения находится в небоскрёбных запросах.
да.
Но это же сам принцип построения программного продукта: "вы можете пользоваться без программистов"
а значит, мы убираем всё, что может напоминать программирование, и заставляем писать необскрёбные запросы.
skalogryz
> Но это же сам принцип построения программного продукта: "вы можете пользоваться без программистов"
Пфффф. Что за глупость.
В запросы непрограммисту вообще нет никакого входа.
Если в коде есть еще возможность осознать зачем та или иная строка существует, то запросы и реляционная алгебра даже для программистам с трудом даётся.
Поэтому нет, не соглашусь.
=A=L=X=
> Пфффф. Что за глупость.
это не моё утверждение.
https://ru.wikipedia.org/wiki/SQL
Первые разработки
Авторы были впечатлены выразительностью и компактностью реляционной алгебры и реляционного исчисления, предложенных (Эдгаром) Коддом, для представления сложных запросов. Кодд использовал символическую запись с математическими обозначениями операций, но Чемберлин и Бойс захотели спроектировать язык так, чтобы им мог воспользоваться любой пользователь, даже не имеющий навыков программирования и знаний математики
skalogryz
Тут да, я тоже неправильно выразился.
Гхм.
Это уже надо в тему про 1С перетаскивать, блин.
Дело в том, что 1С в любой форме пользовательского интерфейса которая насыщается данными из запроса может нажать кнопку "изменить форму...".
И там доступны такие действия как вытащить поле которого изначально в форме не было - но оно есть в таблицах с которыми финальная выборка спрягается.
Или есть возможность для любого поля ссылочной природы (справочник или документ) вытащить поля из его записи в таблице по гуиду. Даже если эта сущность есть поле в изначальном запросе.
Вот эта вот гибкота и настраиваемость была бы невозможной если бы всё это не опиралось на язык SQL и его адаптацию в 1С - язык запросов 1С.
В этом смысле да - это невероятная конфигурируемость и возможности.
Но я завтра доберусь до рабочего стола и скину для примера какой нибудь реальный запрос из бизнеса - вы тут все потухнете расшифровывать что в нём имелось ввиду.
=A=L=X=
> Всё это летит к чертям в SQL-запросах.
Да вроде как раз подходит. В SQL в запросе применяется сразу по много видов конструкций, которые сразу насыпают квадратичную базу, потом множитель по расстоянию от декларации таблицы/колонок/алиасов от мест применения (если декларация таблицы недоступна - то добавка в квадратичную базу, как от конструкций), примерно то же самое для каждой таблицы/колонки/алиаса (умножить на их число), и как раз набегает. Временная таблица сразу даёт проседание, потому что определяется недалеко от основного запроса, и основной запрос уже работает в её терминах, поэтому множитель по расстоянию у символов из основного запроса сильно меньше. Но, если основной запрос снова разрастается с ростом среднего расстояния от символа до декларации временной таблицы, то сложность снова растёт.
skalogryz
> но Чемберлин и Бойс захотели спроектировать язык так, чтобы им мог воспользоваться любой пользователь, даже не имеющий навыков программирования и знаний математики
Хе-хе. И это при том, что у индустрии уже был 15-летний опыт кобола, который прожектировался с вот точно таким же обоснованием.