Автор Тема: [pure С] Макросы как инструмент построения eDSL  (Прочитано 67626 раз)

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
Re:[pure С] Макросы как инструмент построения eDSL
« Ответ #30 : Апрель 06, 2011, 02:53:46 pm »
Возвращаясь к своему варанту решения хочу заметить, что про него правильнее будет сказать "явное", а не "ручное".

Конкретно ручное там:
- последовательная нумерация (без контроля пропусков)
- проверка на последнее значение (ручное) и сброс на начальное (ручное)

Все это "ручное", потому что никак не контролируется компилятором и, в лучшем случае, будет поймано в рантайме на каком-то шаге. А задачка-то - простейшая...

Во-вторых, вариант исполнения процедуры при следущем вызове прописан явно, при помощи глобальной переменной s. Это придаёт определённую гибкость данному решению.

Это придает столько же гибкости сколько и проблем. Кто-то будет не в курсе, что вы где-то особенным образом шаманите с этой s и будет получать "неожиданные" результаты.

Гибкую программу гораздо легче адаптировать к изменившимся требованиям, а автоматизация обычно ведёт к снижению гибкости.

Понятно, что нужен баланс. Исходя из более конкретной задачи. Если решать эту задачу на самом общем (библиотечном) уровне, то я бы однозначно избавился от глобальной (или static) переменной в пользу аргумента, имеющего смысл "текущее состояние".

valexey

  • Administrator
  • Hero Member
  • *****
  • Сообщений: 1990
    • Просмотр профиля
Re:[pure С] Макросы как инструмент построения eDSL
« Ответ #31 : Апрель 06, 2011, 03:08:14 pm »
Вообще говоря, что мой, что Geniepro вариант элементарно (буквально в несколько символов) преобразуется к варианту параметризуемому любой переменной. У Geniepro нужно несколько символов удалить, у меня несколько вставить :-)
"но сейчас, чтобы компенсировать растущую мощность компьютеров, программисты используют фреймворки"

igor

  • Sr. Member
  • ****
  • Сообщений: 438
    • Просмотр профиля
Re:[pure С] Макросы как инструмент построения eDSL
« Ответ #32 : Апрель 06, 2011, 03:38:16 pm »
Конкретно ручное там:
- последовательная нумерация (без контроля пропусков)
Было бы странным городить здесь какую-либо нумерацию, отличную от нумерации, основанной на множестве натуральных чисел. Или Вы предлагаете для этой цели ввести какие-либо идентификаторы? Так это легко можно сделать в секции CONST модуля, если понадобится.

- проверка на последнее значение (ручное) и сброс на начальное (ручное)
Ваше (или чьё-либо ещё) автоматизированное решение никак не избежит такой проверки, просто Вы не будете это видеть в своём автоматизированном коде.

Кто-то будет не в курсе, что вы где-то особенным образом шаманите с этой s и будет получать "неожиданные" результаты.
Документирование модуля никто не отменял. Уж, хотя бы на уровне комментариев. На всякий случай напомню: комментарии должны дополнять исходный текст, а не дублировать его.

... я бы однозначно избавился от глобальной (или static) переменной в пользу аргумента, имеющего смысл "текущее состояние".
А я бы решительно запретил это делать.  :)

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

Кроме того, если ограничить свой выбор каким-либо Оберон-языком, то для решения поставленной тривиальной задачи невозможно избавиться от глобальной переменной. Дело в том, что в этих языках процедура не в состоянии хранить какой-либо контекст после своего завершения: её кадр будет снят со стека вместе со всеми локальными переменными. После неё может остаться только РЕЗУЛЬТАТ её работы. И этот результат она может сохранить для объемлющих блоков только в глобальных по отношению к ней переменных. Всё это называется блочной структурой. Описанные свойства я расцениваю как положительные. Если какой-либо язык нарушает эти принципы, то мне такой язык даром не нужен.
« Последнее редактирование: Апрель 06, 2011, 03:43:11 pm от igor »

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
Re:[pure С] Макросы как инструмент построения eDSL
« Ответ #33 : Апрель 06, 2011, 04:15:30 pm »
Конкретно ручное там:
- последовательная нумерация (без контроля пропусков)
Было бы странным городить здесь какую-либо нумерацию, отличную от нумерации, основанной на множестве натуральных чисел.

А я и не предлагаю. Я говорю, что ее никто не контролирует. Значит возможен человеческий фактор, которому пофиг на ваше "множество натуральных чисел" :)

Или Вы предлагаете для этой цели ввести какие-либо идентификаторы? Так это легко можно сделать в секции CONST модуля, если понадобится.

Нет. Я предлагал список + итератор. В этом случае "сломать" нумерацию, проверку на конец и сброс - невозможно. Написать изначально неправильно (и тут же увидеть, что не работает) - да, можно. Но не потом, когда все работает и надо, например, добавить еще одно состояние. Решение с макросами (при том, что он мне не нравится) тоже свободно от ваших "ручных" недостатков.

- проверка на последнее значение (ручное) и сброс на начальное (ручное)
Ваше (или чьё-либо ещё) автоматизированное решение никак не избежит такой проверки, просто Вы не будете это видеть в своём автоматизированном коде.

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

Кто-то будет не в курсе, что вы где-то особенным образом шаманите с этой s и будет получать "неожиданные" результаты.
Документирование модуля никто не отменял. Уж, хотя бы на уровне комментариев. На всякий случай напомню: комментарии должны дополнять исходный текст, а не дублировать его.

На всякий случай напомню: документирование - последняя и самая неэффективная мера по поддержанию кода в рабочем состоянии. После компилятора и тестов.

... я бы однозначно избавился от глобальной (или static) переменной в пользу аргумента, имеющего смысл "текущее состояние".
А я бы решительно запретил это делать.  :)

В таком случае вы просто не сможете использовать более одного "автомата". Очень странное ограничение для общего решения.

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

Да. И этому есть вполне разумные объяснения. Которые, правда, не всегда доходят, пока не прочувствуешь сам :)

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

Конечно. Я же оговорился - все сильно зависит от конкретных обстоятельств.

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

Вы вообще читаете то, что я пишу? :) Передавайте в качестве аргумента - и все будет возможно :)

Дело в том, что в этих языках процедура не в состоянии хранить какой-либо контекст после своего завершения: её кадр будет снят со стека вместе со всеми локальными переменными. После неё может остаться только РЕЗУЛЬТАТ её работы. И этот результат она может сохранить для объемлющих блоков только в глобальных по отношению к ней переменных. Всё это называется блочной структурой. Описанные свойства я расцениваю как положительные. Если какой-либо язык нарушает эти принципы, то мне такой язык даром не нужен.

Гхм. Если все эти глубокие размышления про блочную структуру всего лишь наезд на сишные static-переменные уровня функций - то мимо :) Они ничем не отличаются от обероновских глобальных переменных, только область видимости у них ограничена функцией. Что, безусловно, однозначный плюс. Особенно, когда вы хотите быть уверенным, что никто не начнет шаманить с "s" за пределами функции ;)
« Последнее редактирование: Апрель 06, 2011, 04:17:51 pm от vlad »

igor

  • Sr. Member
  • ****
  • Сообщений: 438
    • Просмотр профиля
Re:[pure С] Макросы как инструмент построения eDSL
« Ответ #34 : Апрель 06, 2011, 04:47:07 pm »
Вы вообще читаете то, что я пишу? :) Передавайте в качестве аргумента - и все будет возможно :)
Код в студию, пожалуйста.

igor

  • Sr. Member
  • ****
  • Сообщений: 438
    • Просмотр профиля
Re:[pure С] Макросы как инструмент построения eDSL
« Ответ #35 : Апрель 06, 2011, 05:01:56 pm »
Это оно?:

struct context;
typedef void (*F)(context*);
F steps[] = {&step1, &step2, &step3};
int current_step = 0;

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
Re:[pure С] Макросы как инструмент построения eDSL
« Ответ #36 : Апрель 06, 2011, 05:34:43 pm »
Вы вообще читаете то, что я пишу? :) Передавайте в качестве аргумента - и все будет возможно :)
Код в студию, пожалуйста.

библиотечный хедер:
struct stepper_t
{
    virtual ~stepper_t() = 0;
    virtual void next() = 0;
};

typedef std::vector< boost::function<void> > steps_t; // список функций

std::auto_ptr<stepper_t> make_stepper(const steps_t&); // инициализировать автомат списком функций

имплементация:
struct impl : stepper_t
{
    stepper_t(const steps_t &steps) : steps(steps), current(steps.begin()) {assert(this->current != steps.end();}

    virtual void next()
    {
        (*this->current)();
        ++this->current;
        if (this->current == this->steps.end())
            this->current = this->steps.begin();
    }

    steps_t steps;
    steps_t::iterator current;
};

std::auto_ptr<stepper_t> make_stepper(const steps_t& steps)
{
    return std::auto_ptr<stepper_t>(new impl(steps));
}

Использование:
void step1(){printf("step1");}
void step2(){printf("step2");}
...
steps_t steps;
steps.push_back(&step1);
steps.push_back(&step2);
...
std::auto_ptr<stepper_t> test1 = make_stepper(steps); // первый автомат
std::auto_ptr<stepper_t> test2 = make_stepper(steps); // второй автомат
test1->next();
test2->next();
test1->next();
test2->next();

И никаких глобальных переменных :)

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
Re:[pure С] Макросы как инструмент построения eDSL
« Ответ #37 : Апрель 06, 2011, 05:42:31 pm »
И никаких глобальных переменных :)

В данном случае "аргумент" (состояние) про который я говорил - инкапсулирован в самом автомате. Никто не мешает таскать его явно именно именно как аргумент, но это неудобно и будет источником граблей...

valexey

  • Administrator
  • Hero Member
  • *****
  • Сообщений: 1990
    • Просмотр профиля
Re:[pure С] Макросы как инструмент построения eDSL
« Ответ #38 : Апрель 06, 2011, 07:59:26 pm »
А в C++ 2011 это все можно сделать будет уже без уродливых push_back'ов. сразу в фигурных скобках перечислить шаги.

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

valexey

  • Administrator
  • Hero Member
  • *****
  • Сообщений: 1990
    • Просмотр профиля
Re:[pure С] Макросы как инструмент построения eDSL
« Ответ #39 : Апрель 06, 2011, 08:05:03 pm »
Да, это я клоню к тому, что в инструментальном наборе программиста должен быть струмент, позволяющий манипулировать AST (модифицировать, создавать его отдельные куски), чтобы вот такие вот мелкие задачки на местах можно было решать максимально безопасно. (это требуется относительно редко, но иногда этого очень нехватает).
"но сейчас, чтобы компенсировать растущую мощность компьютеров, программисты используют фреймворки"

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
Re:[pure С] Макросы как инструмент построения eDSL
« Ответ #40 : Апрель 06, 2011, 09:08:24 pm »
А в C++ 2011 это все можно сделать будет уже без уродливых push_back'ов. сразу в фигурных скобках перечислить шаги.

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

Но есть нюанс: изначально Geniepro принципиально ради этого не хотел плодить функции, и тем более, методы

Это все понятно... Просто мой вариант - наиболее общий, плюс демонстрация жизни без глобальных переменных :) А в каком-то конкретном случае вполне можно написать и switch по static-переменной...

valexey

  • Administrator
  • Hero Member
  • *****
  • Сообщений: 1990
    • Просмотр профиля
Re:[pure С] Макросы как инструмент построения eDSL
« Ответ #41 : Апрель 06, 2011, 09:58:28 pm »
Наиболее общее решение тут это какой-нибудь boost::fsm :-)
"но сейчас, чтобы компенсировать растущую мощность компьютеров, программисты используют фреймворки"

Peter Almazov

  • Sr. Member
  • ****
  • Сообщений: 482
    • Просмотр профиля
Re:[pure С] Макросы как инструмент построения eDSL
« Ответ #42 : Апрель 07, 2011, 07:26:16 am »
Почему-то никто не вспомнил ключевое слово сопрограмма. Вот как оно должно выглядеть в идеале
step1
resume;
step2
resume;
step3
resume;
step4

Когда-то давно мне пришлось писать BIOS, в котором была процедура вывода символа. И требовалось обрабатывать Esc-последовательности. Типа этого, но не так много, http://www.felixl.com/Uknc_RAM_description_app
Писать конечный автомат для решения такой задачи – скучнейшее занятие, а на то, что получится в результате кодирования лучше не смотреть.
Задача была решена с помощью сопрограмм. Если перевести ассемблер в псевдокод, то получится что-то типа этого (приведены две последовательности):


Пояснение: Esc Y <строка><столбец>  - позиционирование курсора.
<строка> и <столбец> - ASCII-символы с кодами строка+32 и  столбец+32. Если в какой-либо позиции координаты выходят за допустимые пределы, то позиционирование по данному параметру не  производится.

Обратите внимание, что resume идет из недр вложенных скобочных конструкций, поэтому структура программы полностью соответствует структуре данных.
Затраты на реализацию сопрограмм такие: вход в процедуру: одна дополнительная команда (jmp saveAddr), тело процедуры resume: две команды (pop saveAdr; ret). Реально там было еще несколько команд для сохранения/восстановления регистров, но это не связано с сопрограммами.
Сейчас, конечно из за многозадачности, многопоточности, распространения и обработки исключений все не так просто. Ну так я не зря говорил об идеальности.


igor

  • Sr. Member
  • ****
  • Сообщений: 438
    • Просмотр профиля
Re:[pure С] Макросы как инструмент построения eDSL
« Ответ #43 : Апрель 07, 2011, 08:45:37 am »
Код в студию, пожалуйста.

...

И никаких глобальных переменных :)

Да. Вместо одной глобальной переменной у Вас теперь не менее глобальная структура и целая горсть новых идентификаторов: stepper_t, next, steps_t, make_stepper, ... (насколько мне удалось разобраться в чужеродном для меня языке  :))

Цена за такую автоматизацию получается слишком высока.

Это конечно не означает, что Ваше решение не имеет право на жизнь, но я бы в своём коде так делать не стал.

valexey

  • Administrator
  • Hero Member
  • *****
  • Сообщений: 1990
    • Просмотр профиля
Re:[pure С] Макросы как инструмент построения eDSL
« Ответ #44 : Апрель 07, 2011, 09:23:06 am »
Да. Вместо одной глобальной переменной у Вас теперь не менее глобальная структура
Не следует путать объявление переменной с объявлением типа. Последствия в плане глобальности совершенно разные.
"но сейчас, чтобы компенсировать растущую мощность компьютеров, программисты используют фреймворки"