История изменений
Исправление dimgel, (текущая версия) :
А вот теперь продолжим срач! =) Я тут повспоминал, что я делал на макросах.
Первое большое, что вспомнилось – это статически-типизированный DSL, транслирующийся в SQL не в рантайме, а во время компиляции макросами. На скале: и сам делал, и в опенсорсе лежит как минимум одно решение. Но потом вспомнил, что для плюсов есть sqlpp, который тоже транслирует в compile-time. Не помню уже, по какой причине я его забраковал (что-то там было то ли дюже громоздко, то ли дюже коряво), но не суть; будем считать что аналог есть.
А потом вспомнил целый огроменный пласт, которому аналогов на плюсовом «МП» не сделать в приниципе: AOP. Потому что тут переписывется тело метода. На жаве (JEE, Spring, Hibernate) оно интенсивно используется для заворачивания функций в обёртки, управляющие транзакциями, логированием, ленивой загрузкой при обращению к полю сущности и т.п. – в рантайме. В результате серверные жава-приложения стартуют медленно, и стек-трейсы исключений у них неприлично огромные (на каждую спринг-обёртку приходится несколько вызовов).
Так вот, доводилось мне делать свою lombok-аннотацию @Transactional, обрабатываемую соответственно в compile-time. Просто потому что мне нужно было протаскивать доп. параметр, который в стандартных @Transactional отсутствовал.
Жавовские фреймворки в рантайме стандратно создают прокси-класс с такими же сигнатурами методов, что и у оборачиваемого класса; его прокси-методы выполняют требуемые действия и делегируют к методам проксируемого класса.
А на макросах в compile-time я переписываю тело метода (в lombok это AST-узел Block, содержащий список statements, т.е. «{ … }»), помещая этот Block внутрь собственного кода. Совсем грубо, было:
// Наличие lombok-аннотации -- триггер, запускающий мою обработку.
// В скале есть макро-аннотации и макро-функции.
@Transactional
R f(A a, B b, C c) {
ab = a + b;
return ab - c;
}
стало:
R f(A a, B b, C c) { // Сигнатуру не трогаю.
startTransaction();
try { // Исходное тело метода {...} не трогаю.
ab = a + b;
return ab - c;
} catch (Exception e) {
rollback();
throw e;
} finally {
commit();
}
}
Этот пример слишком схематичный и корявый: тут муть с commit() после rollback(). В реале мне, чтобы вообще не касаться и сигнатуры, ни тела метода (не анализировать, не переписывать, в т.ч. не подсовывать commit() перед каждым return), пришлось делать два вложенных try.
UPD. И ещё у меня там был цикл по попыткам при дедлоках.
Ну так вот: ЭТО – метапрограммирование. А в плюсах – пое@$#ь.
Исходная версия dimgel, :
А вот теперь продолжим срач! =) Я тут повспоминал, что я делал на макросах.
Первое большое, что вспомнилось – это статически-типизированный DSL, транслирующийся в SQL не в рантайме, а во время компиляции макросами. На скале: и сам делал, и в опенсорсе лежит как минимум одно решение. Но потом вспомнил, что для плюсов есть sqlpp, который тоже транслирует в compile-time. Не помню уже, по какой причине я его забраковал (что-то там было то ли дюже громоздко, то ли дюже коряво), но не суть; будем считать что аналог есть.
А потом вспомнил целый огроменный пласт, которому аналогов на плюсовом «МП» не сделать в приниципе: AOP. Потому что тут переписывется тело метода. На жаве (JEE, Spring, Hibernate) оно интенсивно используется для заворачивания функций в обёртки, управляющие транзакциями, логированием, ленивой загрузкой при обращению к полю сущности и т.п. – в рантайме. В результате серверные жава-приложения стартуют медленно, и стек-трейсы исключений у них неприлично огромные (на каждую спринг-обёртку приходится несколько вызовов).
Так вот, доводилось мне делать свою lombok-аннотацию @Transactional, обрабатываемую соответственно в compile-time. Просто потому что мне нужно было протаскивать доп. параметр, который в стандартных @Transactional отсутствовал.
Жавовские фреймворки в рантайме стандратно создают прокси-класс с такими же сигнатурами методов, что и у оборачиваемого класса; его прокси-методы выполняют требуемые действия и делегируют к методам проксируемого класса.
А на макросах в compile-time я переписываю тело метода (в lombok это AST-узел Block, содержащий список statements, т.е. «{ … }»), помещая этот Block внутрь собственного кода. Совсем грубо, было:
// Наличие lombok-аннотации -- триггер, запускающий мою обработку.
// В скале есть макро-аннотации и макро-функции.
@Transactional
R f(A a, B b, C c) {
ab = a + b;
return ab - c;
}
стало:
R f(A a, B b, C c) { // Сигнатуру не трогаю.
startTransaction();
try { // Исходное тело метода {...} не трогаю.
ab = a + b;
return ab - c;
} catch (Exception e) {
rollback();
throw e;
} finally {
commit();
}
}
Этот пример слишком схематичный и корявый: тут муть с commit() после rollback(). В реале мне, чтобы вообще не касаться и сигнатуры, ни тела метода (не анализировать, не переписывать, в т.ч. не подсовывать commit() перед каждым return), пришлось делать два вложенных try.
Ну так вот: ЭТО – метапрограммирование. А в плюсах – пое@$#ь.