Рубрика «метапрограммирование» - 4

Возник на днях у нас вопрос: «Как спрятать от любителей hex-редаторов строчки текста в скомпилированном приложении?». Но спрятать так, чтобы это не требовало особых усилий, так, между прочим…
Задача состоит в том, что бы использовать в коде строки как обычно, но при этом в исполняемом файле эти строки в явном виде не хранились, возможности сторонних утилит, которые работают с уже скомпилированными бинарными файлами, задействовать так же не хочется, все нужно делать из обычного C++ кода.
Читать полностью »

Pipe matching в ЯП Clojure (метапрограммирование в Lisp для начинающих) - 1

Введение

Несколько дней назад я открыл для себя замечательный ЯП Clojure — один из современных диалектов Lisp, особенностью которого является хорошая реализация средств многопоточности, компиляция в байткод jvm, соответственно возможность использования java — библиотек, jit-компиляция и т.д. Про Clojure можно почитать например тут. Но в этой статье речь пойдёт о метапрограммировании. Lisp устроен таким образом, что данные и код в нём — одно и то же. Объявления функций, макросов, вызовы функций, развёртывание макросов — в Lisp это всё просто списки, возможно вложенные друг в друга.

(defn square [foo] (* foo foo))
(defmacro show-it [foo] `(println ~foo))

Такое единство кода и данных предоставляет мощные возможности для метапрограммирования — код который пишет код, который пишет код, который пишет код и т.д. — это самое обычное дело для программирования на Lisp. В compile-time нам полностью доступен весь функционал языка, мы можем вызывать функции, развёртывать макросы, возможно рекурсивно. Например, если мы определим вот такой макрос:
Читать полностью »

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

При реализации логгирования, задачи для себя были поставлены следующие:

  • Решить задачу на «мета-уровне», чтобы быть отвязанным от конечной реализации
  • Фронтенд апи для логгирования должен быть простым и прозрачным
  • Иметь возможность выключать ненужные уровни логгирования на этапе компиляции одной константой; например: все что выше LOG_NOTICE не должно попасть в результирующий бинари

Фронтенд выглядит так:

1. В конструкторе CConnection мы логгируем:

TestLog::Log<LOG_NOTICE>() << *this << "connection created";

2. Где CConnection унаследован от

public TLogHeader<'c', CConnection>

3.Который, используя CRTP, знает, что в CConnection есть такое:

	using this_t = CConnection;
	int m_id;           using m_id_t = TParamAccessor<this_t, decltype(this_t::m_id), &this_t::m_id>;
	std::string m_name; using m_name_t = TParamAccessor<this_t, decltype(this_t::m_name), &this_t::m_name>;
    char m_state;       using m_state_t = TParamAccessor<this_t, decltype(this_t::m_state), &this_t::m_state>;
	using log_header_param_list_t = std::tuple<m_id_t, m_name_t, m_state_t>;

3. И превращает эти данные в строчку лога:

c:23:test_conn 1:a:connection created

Где через двоеточие перечислены: с — первый параметр шаблона TLogHeader, и далее значения m_id, m_name, m_state

В моем случае все это дальше пишется в rsyslog и там разбирается в соответствующие поля для MongoDB (в зависимости от типа заголовка, т.е. первый параметр до двоеточия).

Сейчас этот подход у меня в продакшене на высоконагруженной системе, так что любые конструктивные камни будут в пику, или лучше под кат. А если лень, то вот работающий пример на http://coliru.stacked-crooked.com/ т.к. по катом кода на 250 строк, но очень много букв в описании.
Читать полностью »

Язык Julia не поддерживает такую технику программирования, хорошо зарекомендовавшую себя в языках Haskell, Prolog, Erlang, Scala, Mathematica, как pattern matching. Но разрешает писать макросы, которые позволяют исправить этот фатальный недостаток. Выглядит это примерно так:

julia> immutable X a end

julia> immutable Y a ; b end

julia> @case(Y(X(9),2),  Y(4,3)-> 55, Y(X(k),2)->1+k)
10

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

В первой части мы обсудили, как добиться переноса определения шаблона фунции из заголовочного файла в исходник, если набор типов, для которых должен быть инстанциирован шаблон известен заранее. В этой части мы посмотрим, как добиться этого красиво.
Читать полностью »

Введение

Common Lisp, а точнее, его объектная система, CLOS, предоставляет пользователю языка совершенно замечательный механизм, а именно, метаобъектный протокол.

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

Вообще, что такое метаобъектный протокол? Очевидно, это слой объектной системы, который, судя по названию, каким-либо образом оперирует над ней самой, и управляет ей.

Для чего он нужен? На самом деле, в зависимости от языка и объектной системы, список применений может быть практически безграничен. Это как добавление коду декларативности(аннотации в Java и аттрибуты в C#), так и разнообразная генерация кода и классов в рантайме(здесь можно вспомнить разнообразные persistance и ORM фреймворки), так и многое другое.

С моей лично точки зрения, лучше всего метаобъектные протоколы себя зарекомендовали со стороны закрепления паттернов проектирования на уровне объектной системы. Такие паттерны, как, скажем, синглтон, которые в языках без достаточно развитого ООП приходится снова и снова реализовывать методом copy-n-paste, в моем любимом Common Lisp создаются буквально из пары десятков строчек кода и переиспользуются в дальнейшем исключительно указанием метакласса[1].

Тем не менее, в нижеследующем тексте я хочу сосредоточиться на кое-чем более интересном, а именно — на изменении правил работы самой объектной системы, самих ее основ. Именно добавление возможностей подобного изменения и было ключевой целью разработчиков метаобъектного протокола для Common Lisp.

Итак, дальнейший текст будет посвящен созданию прототипной объектной системы, подобной JavaScript, в Common Lisp, с использованием метаобъектного протокола и интеграцией ее в CLOS. Полный код проекта доступен на github[2].

Читать полностью »

Метапрограммирование (с примерами на JavaScript)Эта статья, еще одна попытка переосмысления метапрограммирования, которые я периодически предпринимаю. Идея каждый раз уточняется, но в этот раз удалось подобрать достаточно простых и понятных примеров, которые одновременно очень компактны и иллюстративны, имеют реальное полезное применение и не тянут за собой библиотек и зависимостей. В момент публикации я буду докладывать эту тему на ОдессаJS, поэтому, статью можно использовать, как место для вопросов и комментариев к докладу. Формат статьи дает возможность более полно изложить материал, чем в докладе, слушатели которого, не освобождаются от прочтения.

Популярное понимание метапрограммирования обычно очень размытое, и чаще всего, заканчивается такими вариантами:

  • Шаблоны и макросы, используемые при компиляции
  • Программа, которая изменяет саму себя
  • Программа, генерирующая другую программу

Предлагаю следующее определение:
Метапрограммирование — это парадигма программирования, построенная на программном изменении структуры и поведения программ.
И дальше мы разберем как это работает, зачем это нужно и какие преимущества и недостатки мы получаем в итоге.

Читать полностью »

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

image

Здравствуйте, коллеги.
Хочу рассказать о SFINAE, интересном и очень полезном (к сожалению*) механизме языка C++, который, однако, может представляться неподготовленному человеку весьма мозгоразрывающим. В действительности принцип его использования достаточно прост и ясен, будучи сформулирован в виде нескольких чётких положений. Эта заметка рассчитана на читателей, обладающих базовыми знаниями о шаблонах в C++ и знакомых, хотя бы шапочно, с C++11.
* Почему к сожалению? Хотя использование SFINAE — интересный и красивый приём, переросший в широко используемую идиому языка, гораздо лучше было бы иметь средства, явно описывающие работу с типами.Читать полностью »

Динамическая интерпретация метамоделейПродолжая серию статей по метапрограммированию, подготовил выжимку из достаточно объемной своей работы о повышении уровня абстракций в информационных системах. Хабр конечно любит практические решения, и их таки есть у меня, но материала много и я вынужден разделить его на несколько статей. А для иллюстрации эффективности подхода, могу сказать, что внедрение его во множестве живых проектов позволило повысить эффективность разработки в десятки раз, например, создавать приложения баз данных со структурой в несколько сотен таблиц за неделю и портировать решения между платформами за считанные часы. Эта статья носит характер теоретический и наполнена специфической терминологией, без которой, к сожалению, она была бы значительно объемнее.
Читать полностью »

Недавно мне пришлось работать с кодом, в котором задача передачи параметров произвольных типов решена с использованием стандартных STL контейнеров, параметризованных типом boost::any.
Например:

    void foo (std::vector<boost::any>& args) {
        // do smth.
    }

Предыдущий разработчик был не очень аккуратен и внутри функции работа с содержимым boost::any основывалась на предположении об исходном типе данных, то есть если преобразование boost::any_cast не проходило, то параметр пропускался. В определенных случаях такой способ обработки приемлем и примеры этой методики работы можно посмотреть тут.
Однако, мне хотелось несколько обобщить исходные предположения о типе данных.
Читать полностью »


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js