Scala макросы, где они используются?

Я только заметил, что Scala имеет макросы, но я никогда не видел никакого кода, который их использует. Они также кажутся совершенно отличными от макросов препроцессора C и тому подобного. Прочитав макросы overview, похоже, что они предлагают что-либо, что ранее не было возможно в Scala. Под заголовком мотивации есть список того, что позволяют макросы:

  • Виртуализация языков (перегрузка/переопределение семантики оригинальный язык программирования для обеспечения глубокого внедрения DSL),
  • Обогащение программ (предоставление программам средств для проверки их собственный код),
  • Самооптимизация (самоприменение специфичных для домена оптимизация на основе переопределения программ),
  • Алгоритмическая программа (генерация кода, который утомительно писать с помощью абстракции, поддерживаемые языком программирования).

Позже в меню есть экспериментальные макрофункции, такие как макросы типа, квазикварталы, нетипизированные макросы и даже больше. Ясно, что есть спрос на это!

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

Ответ 1

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

Макросы - это метод метапрограммирования времени компиляции, то есть программные программы. Например, def-macro, который является частью Scala 2.10, хотя и все еще "экспериментальным", выглядит как обычный метод, но всякий раз, когда вы вызываете этот метод в своем коде, компилятор заменит этот вызов тем, что скрывает этот макрос этот метод будет генерировать (новый фрагмент кода).


Очень простой пример. Включите дату, когда ваш проект был скомпилирован в код:

import java.util.Date
import reflect.macros.Context
import language.experimental.macros

object CompileTime {
  def apply(): Date = macro applyImpl

  def applyImpl(c: Context)(): c.Expr[Date] = {
    import c.universe._
    val now     = System.currentTimeMillis() // this is executed during compilation!
    val nowExpr = c.Expr[Long](Literal(Constant(now)))
    val code    = reify(new Date(nowExpr.splice))
    c.Expr(code.tree)
  }
}

Используя этот макрос (следующий код должен быть скомпилирован отдельно от макроса выше):

object MacroTest extends App {
  println(s"This project was compiled on ${CompileTime()}")
}

(Если вы запустили это несколько раз, вы увидите, что время компиляции действительно постоянное)


Итак, макросы предлагают функциональность, которая не была доступна в предыдущей версии Scala. Вы можете делать что-то с помощью макросов, которые вы не можете сделать иначе (часто вы можете писать похожие вещи, используя отражение во время выполнения, но макросы проверяются во время компиляции).

Как пользователь, вы, тем не менее, будете подвергаться воздействию библиотек, которые включают макросы, потому что они могут предоставить мощные конструкции, которые полностью безопасны для типов. Например, автоматические сериализаторы для JSON из класса case могут быть реализованы с помощью макросов, поскольку макрос может проверять тип вашего класса case и строить правильную структуру программы (AST) для чтения и записи этого класса case без опасности времени выполнения отказ.

Некоторые случайные ссылки