Scala 2.10 macros compared to what is available in Java

I do not know this field.

Can someone explain what is possible in Scala 2.10 with macros compared to what is possible in Java with compilation preprocessors and tools like CGLIB, ASM, Byteman ...?

+8
java macros scala
source share
2 answers

[Refresh] . I tried to include an example using Slick . It's hard to summarize many things for a Java audience (not Scala).

Macros in Scala 2.10 bring full-blown metaprogramming into the language as a first-class citizen.

// we often do this: log("(myList++otherList).size: " + (myList++otherList).size) // just to log the string: // "(myList++otherList).size: 42" // Imagine log, if implemented as a macro: log((myList++otherList).size) // could potentially log both the EXPRESSION AND IT VALUE: // "(myList++otherList).size: 42" 

Can functions like this usually be achieved through text preprocessing or bytecode manipulation in a safe and clean way?

Meta-programming at some stage comes down to code generation and is unqualified, it is an umbrella term for various methods - in the interest of "not writing a little code yourself" - if someone were to list some of these methods in some rough order of the stage - from a precompiled source to executing the code, the list may look like this:

  • text source preprocessors (C)
  • templating systems (C ++) (many may argue that the above primitive should be considered)
  • reflection "naturally available" in some dynamic languages ​​(Ruby)
  • reflection at run time in statically typed languages ​​(Java), which provides some dynamism to the language due to type safety.
  • byte code manipulation.

(Note that I omitted the macro systems that are executed at compile time , more about them in the next paragraph.)

First, keep in mind that all of the above methods essentially generate code - whether it is generating / manipulating text source code or generating / manipulating byte code at run time.

What about macro systems? Macros that run during compilation and work not on text source code, nor on compiled bytecode, but at a much more valuable stage - they work on the AST program during compilation and the information available there, and integration with the compilation process makes them some advantages. They are available both in dynamic languages ​​(for example, Lisp and Dylan), and in statically typed languages ​​(Haskell and Scala 2.10 templates self-cleaning macros).

Regarding macros in Scala 2.10, from the top of my head, I would say that the most important advantage would be:

Security type : compilation of preprocessors and manipulation of byte code cannot use the type system. With macros, especially the compile-time macros that Scala 2.10 will have, the Scala macro itself has access to the compiler API. Any kind of static analysis / verification of the source code with full information about the type, which usually, possibly, only at compile time, will be available for macros.

(safe) Syntax extension . Macros allow you to adapt language constructs for a better implementation of DSL. A good example is Slick , a database library that allows you to express SQL queries as safe types of Scala code:

Consider first the usual Scala list processing - for now, we are not talking about databases or macros:

 val coffees : List[Coffee] = // gotten from somewhere // get from this list a list of (name, price) pairs also filtering on some condition for { c <- coffees if c.supID == 101 // ^ comparing an Int to an Int - normal stuff. } yield (c.name, c.price) // For Java programmers, the above is Scala syntactic sugar for coffees.filter(c => c.supId == 101).map(c => (c.name, c.price)) 

Slick, even the non-macro version, allows you to process database tables as if they were a Scala collection: thus, the non-macro version (Slick calls it a raised deployment API) achieves the same, instead of Coffee SQL table:

 // WITHOUT MACROS (using enough of Scala other features): // Generates a query "SELECT NAME,PRICE FROM COFFEES IF SUP_ID = 101" for { c <- Coffees if c.supID === 101 // ^ comparing Rep[Int] to Rep[Int]! // The above is Scala-shorthand for // c <- Coffees if c.supID.===(Const[Int](101)) } yield (c.name, c.price) 

Close enough! But here the === method is used to simulate == , which cannot be used for the obvious reason that you cannot compare the representation of an SQL column with the actual Int .

This is allowed in the macro version if you have Scala 2.10 handy:

 // WITH MACROS: // Generates a query "SELECT NAME,PRICE FROM COFFEES IF SUP_ID = 101" for { c <- coffees if c.supID == 101 // ^ comparing Int to Int! } yield (c.name, c.price) 

So macros are used to provide the same syntax for both SQL and the simple Scala collection. This is a combination of type safety and macro hygiene, in addition to the existing expressiveness and composition available in Scala, which makes macros attractive.

Also, consider this example from the link provided by another answer:

 def assert(cond: Boolean, msg: Any) = macro impl def impl(c: Context)(cond: c.Expr[Boolean], msg: c.Expr[Any]) = if (assertionsEnabled) // if (!cond) raise(msg) If(Select(cond.tree, newTermName("$unary_bang")), Apply(Ident(newTermName("raise")), List(msg.tree)), Literal(Constant(()))) else Literal(Constant(()) 

So, this defines the assert macro, the use of which will resemble a method call:

 import assert assert(2 + 2 == 4, "weird arithmetic") 

Just because assert is a macro, not a method, the Boolean expression 2 + 2 == 4 will only be evaluated if statements have been included . Note that there is a shorthand to help express AST, but this example will hopefully be clearer.

And last but not least, Scala 2.10 macros will be part of the Scala proper - Integrated into the standard distribution - unlike some third-party libraries.

+16
source share

In addition to the points mentioned by Fayz, Scala hygienic macros: they will not suffer from accidental capture of identifiers, In particular, Scala macros self-cleaning : hygiene is achieved through reification, where patronage itself is a macro. For a deeper understanding of how this works, see Scala Macros, technical report .

+4
source share

All Articles