xeno_by (xeno_by) wrote,
xeno_by
xeno_by

Category:

Макросы vs шаблоны

Продолжая дискуссию про метапрограммирование в D: http://thedeemon.livejournal.com/68456.html.

С одной стороны, дишный стиль МП кажется очень адхочным, но, с другой стороны, поверхностное знакомство и отзывы автора журнала оставляют впечатление чего-то крайне легкого в использовании. Цитируя уважаемого thedeemon:
Я видел много разных попыток сделать удобные лисп-стайл макросы (camlp4, nemerle, haxe, какие-то кусочки скалы...), и везде это пляски с бубном, часто отдельные фазы компиляции, отдельный синтаксис и длинное страшное слово "метапрограммирование". В D же просто берешь и пишешь generic код, даже и мысль о таком длинном слове не приходит.
Вот, например, надо сгенерировать класс, который в зависимости от типа, передаваемого в генератор, будет иметь или не иметь какие-то мемберы [1].

Макросы

В скале мы пишем макрос, который заворачивает шаблон класса в квазицитату. В эту квазицитату мы сплайсим условно генерируемые кусочки. Например, вот так:
val length = if (R.method("hasLength").exists) q"..." else EmptyTree
val empty = if (isInfinite(R)) q"..." else EmptyTree
q"""
  class MyRange {
    val innerRange: R = ...
    ... // code that exists in all instantiations of MyRange
    $length
    $empty
  }
"""
Да, классно, что есть полноценный рефлекшен API вместо пачки захардкодженных в язык __traits и основанных на них самописных темплейтах, которые, например, делают is(typeof(...)). Да, классно, что сниппеты кода являются первоклассными сущностями и что, соответственно, нет проблем их модуляризировать как угодно. Да, классно, что МП реализуется только макросами, а не кучей языковых фич вроде alias, enum, template, и так далее [2, 3].

Шаблоны

Но все же, посмотрите, как задорно выглядит дишный вариант! (Ниже приведена моя личная экстраполяция примера из книжки, может содержать ошибки). Заметьте отсутствие ада метауровней вида q"бла" бла бла q"бла бла" бла q"бла" (что-то похожее мы обсуждали на scala-internals в контексте тайп макросов [4]). Понятное дело, метауровни никуда не делись - они просто перемешались с генерируемым кодом, но насколько стало удобнее читать:
struct MyRange(R) {
  R innerRange;
  ... // code that exists in all instantiations of MyRange
  static if (hasLength!R)
    auto length() { return innerRange.length; }
  static if (isInfinite!R)
    enum bool empty = false;
}

Вопрос

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

Предлагаю оставить в стороне проблемы имплементации того или иного стиля (падения компилятора на сложных темплейтах, сырость первой (экспериментальной!) версии макросов в Скале 2.10, и так далее). Предположим, что подлежащие реализации работают идеально без глюков.

Также хочу отметить, что не принимается ответ "макросы круче потому, что на них можно реализовать темплейты". Вопрос не в том, какой фундамент для МП теоретически более элегантный, а в том, какой тул вам было бы приятнее использовать, независимо от того, на чем именно этот тул реализован.

Ссылки

[1] https://github.com/PhilippeSigaud/D-templates-tutorial/raw/master/D-templates-tutorial.pdf, страница 21, раздел "Optional code"
[2] http://dicebot.blogspot.ch/2013/04/7-trivial-tips-for-compile-time-meta.html, часть 1
[3] http://xeno-by.livejournal.com/86259.html
[4] https://groups.google.com/d/msg/scala-internals/91W0-PxMQ9Q/hq5n47RxfN8J
Tags: macros, scala
Subscribe
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic
  • 19 comments