Плетение байт-кода против макросов Lisp

11

Я читал о библиотеках, написанных людьми для таких языков, как Java и C #, в которых используется переплетение байт-кода для таких вещей, как перехват вызовов функций, вставка кода регистрации и т. Д. Я также читал в макросах Lisp / Clojure в попытаться лучше понять, как их использовать. Чем больше я читаю о макросах, тем больше кажется, что они предоставляют ту же функциональность, что и библиотеки для создания байт-кода. Под функциональностью я подразумеваю способность манипулировать кодом во время компиляции.

Примерами библиотек, которые я просматривал, были AspectJ, PostSharp и Cecil.

Есть ли что-нибудь, что можно сделать с одним, а не с другим? Они действительно решают те же проблемы, или я сравниваю яблоки и апельсины?

mortalapeman
источник
2
Создание байтового кода - это
обходной путь,
2
@kevincline Вы серьезно пытаетесь начать этот старый бой?
Джонатан Хенсон

Ответы:

10

Плетение байт-кода и макросы - это две разные вещи.

Переплетение байтового кода - это способ перехвата вызовов функций, так что вы можете внедрить какую-то функциональность (обычно сквозную задачу, такую ​​как ведение журнала) в вызов функции, либо до, либо после выполнения функции. Переплетение байтового кода выполняется на уровне байтового кода, что означает, что это происходит после компиляции. На саму функцию это не влияет. Это один из методов, которые использует Аспектно-ориентированное программирование .

Макросы - это способ расширить синтаксис языка. В своей простейшей форме макрос - это просто способ записывать нажатия клавиш, а затем воспроизводить их с помощью горячих клавиш. Языковые макросы работают аналогичным образом; ключевое слово или другая синтаксическая конструкция заменяет некоторое расширение макроса. Это упрощенно, конечно; лучший пример макроса, специфичного для Lisp, можно найти здесь .

Роберт Харви
источник
+1 за упоминание, что это ключевой способ реализации АОП.
Джонатан Хенсон
И транзакции ... давайте не будем забывать транзакции.
Джонатан Хенсон
3
Макросы LISP - это не что иное, как «способ записи нажатий клавиш».
Кевин Клайн
1
Ну, некоторые фундаментальные понятия отсутствуют в ответе IMO, это могут быть: AST, рефлексия, мета-округлость.
AndreasScheinert
2
@AndreasScheinert: ОП не спрашивал ни о одной из этих вещей. Это не диссертация; это просто ответ на вопрос ОП.
Роберт Харви
5

Хотя они могут использоваться для одной и той же цели, макросы LISP сильно отличаются от плагинов для создания байт-кода Java. Макросы LISP расширяют синтаксис LISP на уровне исходного кода LISP. Поскольку макросы LISP пишутся на том же уровне, что и другой код LISP, они являются широко используемой языковой функцией.

Подключаемые модули Java для создания байт-кода работают на уровне JVM. Хотя многие Java-программисты могут использовать плагины для создания байт-кода, написанные другими, очень немногие Java-программисты пишут свои собственные плагины для создания байт-кода.

Часть работы, выполняемой плагинами компилятора Java, очень легко выполняется на динамических языках. Перехват вызова функции особенно прост.

Кевин Клайн
источник
Я понимаю технические различия между ними. Я пытался взглянуть на вопрос с точки зрения высокого уровня. Могут ли оба инструмента манипулировать кодом для достижения одинаковых целей? Есть ли какие-либо проблемы, которые макросы не могут решить, как это может сделать манипуляция с байт-кодом (разумным и экономически эффективным образом)? Это больше, чем я собирался.
смертный человек
@mortalapeman: манипуляции, которые возможны в Java и C # с помощью модификации байт-кода, могут выполняться непосредственно в таких языках, как Lisp, Ruby, Python, Lua, Javascript ... Предположительно возможно сделать все, что макрос LISP может сделать через байт - манипулирование кодом, но на практике этого не происходит.
Кевин Клайн
4

Макросы Lisp работают на уровне исходного кода. Если вы оберните какой-нибудь макрос вокруг фрагмента кода, то вы сможете сделать много вещей. Включая анализ исходного кода, вставку кода, переписывание кода и т. Д.

Если вы хотите изменить вызовы функций, Лисп обычно использует два механизма:

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

  • Реализации на Лиспе иногда предоставляют функцию под названием «совет». Это позволяет выполнять код до, после или вокруг вызовов. Например, в LispWorks: Совет .

Таким образом, вы можете перехватывать вызовы без низкоуровневой обработки кода.

Райнер Йосвиг
источник