[prev in list] [next in list] [prev in thread] [next in thread] 

List:       groovy-dev
Subject:    Re: [groovy-dev] State of the macros
From:       <cedric.champeau () gmail ! com>
Date:       2014-10-20 17:57:48
Message-ID: 54454D1C.4080400 () gmail ! com
[Download RAW message or body]

It's a bit soon to talk about limitations, but I expect problems with 
generics, as well as the syntax to transform statements (it is easy to 
transform an expression into another expression,but transforming a 
statement is more complex).

On 17/10/2014 19:34, ngalarneau@ABINITIO.COM wrote:
> Cedric,
> 
> That looks exciting!
> 
> What limitations do you foresee?
> 
> 
> Neil
> 
> 
> 
> 
> From: Cédric Champeau <cedric.champeau@gmail.com>
> To: dev@groovy.codehaus.org,
> Date: 10/17/2014 12:43 PM
> Subject: Re: [groovy-dev] State of the macros
> ------------------------------------------------------------------------
> 
> 
> 
> So here is the update for the end of the week. I worked with Sergei on 
> improving the macro system on two aspects:
> 
> 1. being able to generate classes with macros
> 2. providing an AST matcher
> 
> I think 2 is very important if we want to simplify AST xforms. 
> Basically, if you need an AST transform to trigger on a specific 
> condition (like matching a method call of a certain form), it can be 
> very complicated and require a lot of boilerplate code. So the idea 
> would be to provide AST matching, where you would describe what you 
> look for, and the matching engine would return the list of AST nodes 
> that match. The good news is that I have a prototype working, and you 
> can already take a look at some code samples here: 
> _https://github.com/melix/groovy-core/blob/d42fd1b39c5c421daf6cacb45403f8dcb06f8f12/ \
> subprojects/groovy-macro/src/test/groovy/org/codehaus/groovy/macro/matcher/ASTMatcherTest.groovy#L35_
>  
> The API is far from being final, and as an example, I wrote an example 
> that illustrates what it could, in the end, look like:
> 
> def ast = macro {
> 
> println((a*b)+(a*c))
> 
> }
> 
> use(ASTMatcher) {
> 
> def pattern = macro {
> 
> (a*b)+(a*c)
> 
> }
> 
> def replacement = macro {
> 
> a*(b+c)
> 
> }
> 
> def result = ast.replace(pattern).with(replacement)
> 
> def expected = macro {
> 
> println (a*(b+c))
> 
> }
> 
> assert result.matches(expected)
> 
> }
> 
> 
> 
> What do you think?
> 
> Last but not least, the more I work with macros, the less I feed the 
> need for the global AST transformation. I think annotating the code 
> that uses the "macro" block with a local AST xform would be enough. 
> Thoughts?
> 
> 
> On 07/10/2014 19:46, Sergei Egorov wrote:
> Great brief, Cedric!
> 
> I'm here and ready to discuss both features.
> 
> Just want to add few things:
> 
> * MacroGroovy already can be used inside @Macro methods
> * The reason why I'm created @Macro extension methods (MEMs) is
> simple: I decided to extract code base from MacroGroovy, because
> it can be used outside of "AST nodes generation" context.
> * MEMs are implemented with Global AST transformation with method
> call scanning, and it costs. But, there are already almost the
> same transformation called AstBuilderTransformation. Most
> important, it can be replaced with @Macro method with
> backward compatibility. So, it's not about new global xform. Just
> rethinking of old one.
> 
> 
> 
> 
> 
> On Tue, Oct 7, 2014 at 8:20 PM, Cédric Champeau 
> <_cedric.champeau@gmail.com_ <mailto:cedric.champeau@gmail.com>> wrote:
> Hi everyone,
> 
> You may know that we have long been complaining about the complexity 
> of AST transformations in Groovy. There are a very powerful tool, but 
> it is still a bit complex to handle. In Groovy 2.4, we planned to 
> integrate work from Sergei Egorov (@bsideup) that he called "Groovy 
> macros". Basically the idea is to have a simple way to replace classic 
> method class into more complex expressions. In this email, I'll try to 
> summarize the project and give some ideas about the orientations we 
> want for the Groovy language. In the end, your opinion matters so 
> please feel free to comment.
> 
> First of all, Sergei actually worked on two "macro" projects. The 
> first one consists of a "macro" block that can be illustrated by this:
> *def *someVariable = *new *VariableExpression(*"someVariable"*);
> 
> ReturnStatement result = macro {
> *return new *NonExistingClass($v{someVariable});
> }
> 
> As you can see, it is some kind of "super AstBuilder" which is capable 
> of handling variables/expressions from an external context thanks to 
> proper escaping with $v. This macro code is primarily aimed at being 
> used inside AST transformation themselves, and dramatically reduce the 
> amount of code required to generate an AST tree. An advantage of those 
> macro blocks is that if you use them in AST transformations, you're 
> actually not limited to expressions. You can generate anything, as 
> long as what is inside the macro { ... } block is supported by the 
> Groovy syntax. A drawback of the current implementation is that it 
> uses a global AST transformation. So as soon as you have the macro 
> project on classpath, every single method call corresponding to 
> "macro" will be interpreted as a macro block. There are multiple 
> disadvantages of global AST transformations. First of all, they are, 
> as the name says, global, meaning that they apply independently on 
> *every* class being compiled by Groovy. This also means that the 
> transformation is run even if you know the code you write is not using 
> it. In particular, we need to inspect the full AST, in-depth, to find 
> potential method calls named "macro" even if there's not a single one 
> in the code (because you will only know once you have visited the full 
> AST). In short, a global AST transformation has a clear performance 
> impact, because it is executed independently of the context. For the 
> macro stuff, an easy workaround would be to transform the global AST 
> transformation into a local one. For example, an AST transformation 
> using the macro system could declare it by annotating with 
> @EnableMacros. I think it is reasonable, since it is very unlikely 
> that you would use the macro { ... } stuff in regular code. The macro 
> block is indeed useful, but in the end, it is limited to writing other 
> AST transformations that would be either global or local. In short, 
> the current macro { ... } block is useful for AST transformation 
> designers, but cannot be used by "regular" Groovy users to define new 
> language constructs.
> 
> In answer to that problem, Sergei worked on a second implementation of 
> macros named @Macro. The idea is both simple and elegant. Just like 
> you can define extension methods in Groovy (see 
> _http://docs.groovy-lang.org/2.3.7/html/documentation/#_extension_modules_), 
> you can write a macro like this:
> 
> *public class *TestMacroMethods {
> 
> @Macro
> *public static *Expression safe(MacroContext macroContext, 
> MethodCallExpression callExpression) {
> *return */ternaryX/(
> /notNullX/(callExpression.getObjectExpression()),
> callExpression,
> /constX/(*null*)
> );
> }
> }
> 
> and for this to work, TestMacroMethods needs to be declared as a 
> regular Groovy extension module. In that case, *any* code using "safe" 
> would be transformed, so:
> 
> safe(x.foo()).bar()
> 
> will be expanded *at compile time* into x.foo?x.foo().bar():null
> 
> A more interesting example with pattern matching can be found here: 
> _https://github.com/bsideup/groovy-pattern-match/blob/master/src/main/java/ru/trylogic/groovy/pattern/PatternMatchingMacroMethods.java_
>  
> An important thing to understand is that the @Macro annotation is 
> *not* an AST transformation. Instead, it's a marker annotation which 
> is looked up at compile time, for each method call. So for each method 
> call of the AST, we try to find if an extension method node of the 
> same name exists, is annotated with @Macro and takes MacroContext as 
> the first argument and in that case, the original method call is 
> transformed thanks to the extension method at compile time. The code 
> of the macro itself is regular AST transformation code. It does *not* 
> use the macro stuff from the first implementation, hence doesn't 
> simplify writing xforms. On the other hand, it greatly simplifies the 
> availability of transforms by making them writable as simple extension 
> methods, without the need of ceremony (annotations). It is actually 
> very cool, but it comes at a price. Performance wise, it is still a 
> global AST transformation, but worse, for each and every call, it 
> implies finding an extension method node. It can (and will) cost a 
> lot, but we can improve the situation by introducing specific caches. 
> Moreover, it also implies that the sole fact of adding a macro "jar" 
> on classpath could potentially affect the semantics of your program: 
> if a method call in your code matches the name of a macro method call, 
> then it would be applied at compile time. Of course, one could argue 
> that it is already the case for extension modules, but the risk is 
> lower: for extension modules, the only cases of conflicts is when the 
> receiver of the message matches the class of the extension module. For 
> @Macro, any method call on "implicit this" would be matched. This 
> draws the point of whether the @Macro stuff should also be combined 
> with a @UseMacro local AST transformation, in order to avoid the 
> problem of the global one.
> 
> If we do, then definitely, the performance issue is not one anymore, 
> because only marked code would be transformed. On the other hand, we 
> introduce ceremony again, which would mean that we loose the benefit 
> of extension methods being transparently visible. In the case of the 
> pattern matching stuff, this would mean that you would have to 
> explicitly annotate your code to enable the feature. Is it a problem? 
> I'm not sure actually. Also it's worth noting that the global AST 
> transformation issue is less of a problem if you have lots of macros 
> on classpath, because a single transformation would apply them all in 
> a single pass.
> 
> Last but not least, my feeling is that what we need is something in 
> between the first macro implementation and the second one. In 
> particular, I would like to be able to write the @Macro method body 
> using those macro { ... } blocks. It makes a lot of sense to me. Next, 
> I wouldn't like to be limited to expressions. I think a macro should 
> be able to produce any AST node. This implies expressions, but also 
> statements or even full methods.
> 
> I gave an example a little contrived, I admit, to Sergei, which is, 
> imagine that I want to generate two methods with the same body, but 
> accepting two different argument types. Then I could write a macro 
> that generates the method:
> 
> @Macro MethodNode createMultiply(MacroContext ctx, ClassNode argType) {
> macro {
> _argType_ multByTwo(_argType_ x) { 2 }
> }
> }
> 
> Then in a class I could write:
> 
> class Calculator {
> createMultiply int
> createMultiply double
> }
> 
> Of course, this wouldn't compile because the grammar wouldn't allow 
> defining a method in a closure (in the macro block), and it would not 
> recognize the createMultiply calls directly in the class body, but I 
> kind of like the idea of a macro system that just allows expanding and 
> reasoning at the AST level anywhere, because it lets us create new 
> language constructs.
> 
> In any case, let us know what you think, what you expect from a macro 
> system in Groovy. We have very good starting points, let's make it 
> rock solid :-)
> -- 
> Cédric Champeau
> SpringSource - Pivotal
> _http://twitter.com/CedricChampeau_
> _http://melix.github.io/blog_
> _http://spring.io/__http://www.gopivotal.com/_
> 
> 
> 
> 
> -- 
> Best regards,
> Sergei Egorov
> 
> 
> -- 
> Cédric Champeau
> SpringSource - Pivotal
> _http://twitter.com/CedricChampeau_
> _http://melix.github.io/blog_
> _http://spring.io/__http://www.gopivotal.com/_
> 
> 
> 
> 
> NOTICE /from Ab Initio: This email (including any attachments) may 
> contain information that is subject to confidentiality obligations or 
> is legally privileged, and sender does not waive confidentiality or 
> privilege. If received in error, please notify the sender, delete this 
> email, and make no further use, disclosure, or distribution. / 


-- 
Cédric Champeau
SpringSource - Pivotal
http://twitter.com/CedricChampeau
http://melix.github.io/blog
http://spring.io/ http://www.gopivotal.com/


[Attachment #3 (text/html)]

<html>
  <head>
    <meta content="text/html; charset=windows-1252"
      http-equiv="Content-Type">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    <div class="moz-cite-prefix">It's a bit soon to talk about
      limitations, but I expect problems with generics, as well as the
      syntax to transform statements (it is easy to transform an
      expression into another expression,but transforming a statement is
      more complex).<br>
      <br>
      On 17/10/2014 19:34, <a class="moz-txt-link-abbreviated" \
href="mailto:ngalarneau@ABINITIO.COM">ngalarneau@ABINITIO.COM</a> wrote:<br>  </div>
    <blockquote
cite="mid:OFBB777D6B.77E00EEE-ON85257D74.005FF70F-85257D74.006081D7@abinitio.com"
      type="cite"><font face="sans-serif" size="2">Cedric,</font>
      <br>
      <br>
      <font face="sans-serif" size="2">That looks exciting!</font>
      <br>
      <br>
      <font face="sans-serif" size="2">What limitations do you foresee?</font>
      <br>
      <br>
      <br>
      <font face="sans-serif" size="2">Neil</font>
      <br>
      <br>
      <br>
      <br>
      <br>
      <font color="#5f5f5f" face="sans-serif" size="1">From:      
         </font><font face="sans-serif" size="1">Cédric Champeau
        <a class="moz-txt-link-rfc2396E" \
href="mailto:cedric.champeau@gmail.com">&lt;cedric.champeau@gmail.com&gt;</a></font>  \
<br>  <font color="#5f5f5f" face="sans-serif" size="1">To:      
         </font><font face="sans-serif" size="1"><a class="moz-txt-link-abbreviated" \
href="mailto:dev@groovy.codehaus.org">dev@groovy.codehaus.org</a>,  </font>
      <br>
      <font color="#5f5f5f" face="sans-serif" size="1">Date:      
         </font><font face="sans-serif" size="1">10/17/2014 12:43 PM</font>
      <br>
      <font color="#5f5f5f" face="sans-serif" size="1">Subject:    
           </font><font face="sans-serif" size="1">Re: [groovy-dev]
        State of the macros</font>
      <br>
      <hr noshade="noshade">
      <br>
      <br>
      <br>
      <font size="3">So here is the update for the end of the week. I
        worked
        with Sergei on improving the macro system on two aspects:<br>
        <br>
            1. being able to generate classes with macros<br>
            2. providing an AST matcher<br>
        <br>
        I think 2 is very important if we want to simplify AST xforms.
        Basically,
        if you need an AST transform to trigger on a specific condition
        (like matching
        a method call of a certain form), it can be very complicated and
        require
        a lot of boilerplate code. So the idea would be to provide AST
        matching,
        where you would describe what you look for, and the matching
        engine would
        return the list of AST nodes that match. The good news is that I
        have a
        prototype working, and you can already take a look at some code
        samples
        here: </font><a moz-do-not-send="true"
href="https://github.com/melix/groovy-core/blob/d42fd1b39c5c421daf6cacb45403f8dcb06f8f \
12/subprojects/groovy-macro/src/test/groovy/org/codehaus/groovy/macro/matcher/ASTMatcherTest.groovy#L35"><font
  color="blue" size="3"><u>https://github.com/melix/groovy-core/blob/d42fd1b39c5c421da \
f6cacb45403f8dcb06f8f12/subprojects/groovy-macro/src/test/groovy/org/codehaus/groovy/macro/matcher/ASTMatcherTest.groovy#L35</u></font></a><font
  size="3"><br>
        <br>
        The API is far from being final, and as an example, I wrote an
        example
        that illustrates what it could, in the end, look like:<br>
      </font>
      <br>
      <tt><font size="3">def ast = macro {<br>
        </font></tt>
      <br>
      <tt><font size="3">           
          println((a*b)+(a*c))<br>
        </font></tt>
      <br>
      <tt><font size="3">        }<br>
        </font></tt>
      <br>
      <tt><font size="3">        use(ASTMatcher)
          {<br>
        </font></tt>
      <br>
      <tt><font size="3">           
          def pattern = macro {<br>
        </font></tt>
      <br>
      <tt><font size="3">               
          (a*b)+(a*c)<br>
        </font></tt>
      <br>
      <tt><font size="3">           
          }<br>
        </font></tt>
      <br>
      <tt><font size="3">           
          def replacement = macro {<br>
        </font></tt>
      <br>
      <tt><font size="3">               
          a*(b+c)<br>
        </font></tt>
      <br>
      <tt><font size="3">           
          }<br>
        </font></tt>
      <br>
      <tt><font size="3">           
          def result = ast.replace(pattern).with(replacement)<br>
        </font></tt>
      <br>
      <tt><font size="3">           
          def expected = macro {<br>
        </font></tt>
      <br>
      <tt><font size="3">               
          println (a*(b+c))<br>
        </font></tt>
      <br>
      <tt><font size="3">           
          }<br>
        </font></tt>
      <br>
      <tt><font size="3">           
          assert result.matches(expected)<br>
        </font></tt>
      <br>
      <tt><font size="3">        }<br>
        </font></tt>
      <br>
      <font size="3"><br>
        <br>
        What do you think?<br>
        <br>
        Last but not least, the more I work with macros, the less I feed
        the need
        for the global AST transformation. I think annotating the code
        that uses
        the "macro" block with a local AST xform would be enough.
        Thoughts?<br>
        <br>
        <br>
        On 07/10/2014 19:46, Sergei Egorov wrote:</font>
      <br>
      <font size="3">Great brief, Cedric! </font>
      <br>
      <br>
      <font size="3">I'm here and ready to discuss both features. </font>
      <br>
      <br>
      <font size="3">Just want to add few things:</font>
      <ul>
        <li><font size="3">MacroGroovy already can be used inside @Macro
            methods</font>
        </li>
        <li><font size="3">The reason why I'm created @Macro extension
            methods (MEMs)
            is simple: I decided to extract code base from MacroGroovy,
            because it
            can be used outside of "AST nodes generation" context. </font>
        </li>
        <li><font size="3">MEMs are implemented with Global AST
            transformation with
            method call scanning, and it costs. But, there are already
            almost the same
            transformation called AstBuilderTransformation. Most
            important, it can
            be replaced with @Macro method with backward compatibility.
            So, it's
            not about new global xform. Just rethinking of old one. </font></li>
      </ul>
      <br>
      <br>
      <br>
      <br>
      <font size="3">On Tue, Oct 7, 2014 at 8:20 PM, Cédric Champeau
        &lt;</font><a moz-do-not-send="true"
        href="mailto:cedric.champeau@gmail.com" target="_blank"><font
          color="blue" size="3"><u>cedric.champeau@gmail.com</u></font></a><font
        size="3">&gt;
        wrote:</font>
      <br>
      <font size="3">Hi everyone,<br>
        <br>
        You may know that we have long been complaining about the
        complexity of
        AST transformations in Groovy. There are a very powerful tool,
        but it is
        still a bit complex to handle. In Groovy 2.4, we planned to
        integrate work
        from Sergei Egorov (@bsideup) that he called "Groovy macros".
        Basically the idea is to have a simple way to replace classic
        method class
        into more complex expressions. In this email, I'll try to
        summarize the
        project and give some ideas about the orientations we want for
        the Groovy
        language. In the end, your opinion matters so please feel free
        to comment.<br>
        <br>
        First of all, Sergei actually worked on two "macro" projects.
        The first one consists of a "macro" block that can be
        illustrated
        by this:</font>
      <br>
      <font color="#000061" face="Source Code Pro" size="2"><b>def </b></font><font
        color="#000080" face="Source Code Pro" size="2">someVariable
      </font><font face="Source Code Pro" size="2">= </font><font
        color="#000061" face="Source Code Pro" size="2"><b>new
        </b></font><font face="Source Code Pro" \
                size="2">VariableExpression(</font><font
        color="#008000" face="Source Code Pro" \
size="2"><b>"someVariable"</b></font><font  face="Source Code Pro" size="2">);<br>
        <br>
        ReturnStatement </font><font color="#000080" face="Source Code
        Pro" size="2">result
      </font><font face="Source Code Pro" size="2">= macro {<br>
           </font><font color="#000061" face="Source Code Pro" size="2"><b>return
new
        </b></font><font face="Source Code Pro" \
                size="2">NonExistingClass($v{</font><font
        color="#000080" face="Source Code Pro" size="2">someVariable</font><font
        face="Source Code Pro" size="2">});<br>
        }<br>
      </font>
      <br>
      <font size="3">As you can see, it is some kind of "super
        AstBuilder"
        which is capable of handling variables/expressions from an
        external context
        thanks to proper escaping with $v. This macro code is primarily
        aimed at
        being used inside AST transformation themselves, and
        dramatically reduce
        the amount of code required to generate an AST tree. An
        advantage of those
        macro blocks is that if you use them in AST transformations,
        you're actually
        not limited to expressions. You can generate anything, as long
        as what
        is inside the macro { ... } block is supported by the Groovy
        syntax. A
        drawback of the current implementation is that it uses a global
        AST transformation.
        So as soon as you have the macro project on classpath, every
        single method
        call corresponding to "macro" will be interpreted as a macro
        block. There are multiple disadvantages of global AST
        transformations.
        First of all, they are, as the name says, global, meaning that
        they apply
        independently on *every* class being compiled by Groovy. This
        also means
        that the transformation is run even if you know the code you
        write is not
        using it. In particular, we need to inspect the full AST,
        in-depth, to
        find potential method calls named "macro" even if there's not
        a single one in the code (because you will only know once you
        have visited
        the full AST). In short, a global AST transformation has a clear
        performance
        impact, because it is executed independently of the context. For
        the macro
        stuff, an easy workaround would be to transform the global AST
        transformation
        into a local one. For example, an AST transformation using the
        macro system
        could declare it by annotating with @EnableMacros. I think it is
        reasonable,
        since it is very unlikely that you would use the macro { ... }
        stuff in
        regular code. The macro block is indeed useful, but in the end,
        it is limited
        to writing other AST transformations that would be either global
        or local.
        In short, the current macro { ... } block is useful for AST
        transformation
        designers, but cannot be used by "regular" Groovy users to
        define
        new language constructs.<br>
        <br>
        In answer to that problem, Sergei worked on a second
        implementation of
        macros named @Macro. The idea is both simple and elegant. Just
        like you
        can define extension methods in Groovy (see </font><a
        moz-do-not-send="true"
href="http://docs.groovy-lang.org/2.3.7/html/documentation/#_extension_modules"
        target="_blank"><font color="blue" \
size="3"><u>http://docs.groovy-lang.org/2.3.7/html/documentation/#_extension_modules</u></font></a><font
  size="3">),
        you can write a macro like this:<br>
      </font>
      <br>
      <font color="#000080" face="Source Code Pro" size="2"><b>public
          class </b></font><font face="Source Code Pro" size="2">TestMacroMethods
        {<br>
           <br>
           </font><font color="#808000" face="Source Code Pro" size="2">@Macro<br>
           </font><font color="#000080" face="Source Code Pro" size="2"><b>public
static
        </b></font><font face="Source Code Pro" size="2">Expression
        safe(MacroContext
        macroContext, MethodCallExpression callExpression) {<br>
               </font><font color="#000080" face="Source Code Pro"
        size="2"><b>return
        </b></font><font face="Source Code Pro" size="2"><i>ternaryX</i>(<br>
                       <i>notNullX</i>(callExpression.getObjectExpression()),<br>
                       callExpression,<br>
                       <i>constX</i>(</font><font color="#000080"
        face="Source Code Pro" size="2"><b>null</b></font><font
        face="Source Code Pro" size="2">)<br>
               );<br>
           }<br>
        }</font><font face="Source Code Pro" size="6"><br>
      </font>
      <br>
      <font size="3">and for this to work, TestMacroMethods needs to be
        declared
        as a regular Groovy extension module. In that case, *any* code
        using "safe"
        would be transformed, so:<br>
        <br>
        safe(x.foo()).bar()<br>
        <br>
        will be expanded *at compile time* into x.foo?x.foo().bar():null<br>
        <br>
        A more interesting example with pattern matching can be found
        here: </font><a moz-do-not-send="true"
href="https://github.com/bsideup/groovy-pattern-match/blob/master/src/main/java/ru/trylogic/groovy/pattern/PatternMatchingMacroMethods.java"
  target="_blank"><font color="blue" \
size="3"><u>https://github.com/bsideup/groovy-pattern-match/blob/master/src/main/java/ru/trylogic/groovy/pattern/PatternMatchingMacroMethods.java</u></font></a><font
  size="3"><br>
        <br>
        An important thing to understand is that the @Macro annotation
        is *not*
        an AST transformation. Instead, it's a marker annotation which
        is looked
        up at compile time, for each method call. So for each method
        call of the
        AST, we try to find if an extension method node of the same name
        exists,
        is annotated with @Macro and takes MacroContext as the first
        argument and
        in that case, the original method call is transformed thanks to
        the extension
        method at compile time. The code of the macro itself is regular
        AST transformation
        code. It does *not* use the macro stuff from the first
        implementation,
        hence doesn't simplify writing xforms. On the other hand, it
        greatly simplifies
        the availability of transforms by making them writable as simple
        extension
        methods, without the need of ceremony (annotations). It is
        actually very
        cool, but it comes at a price. Performance wise, it is still a
        global AST
        transformation, but worse, for each and every call, it implies
        finding
        an extension method node. It can (and will) cost a lot, but we
        can improve
        the situation by introducing specific caches. Moreover, it also
        implies
        that the sole fact of adding a macro "jar" on classpath could
        potentially affect the semantics of your program: if a method
        call in your
        code matches the name of a macro method call, then it would be
        applied
        at compile time. Of course, one could argue that it is already
        the case
        for extension modules, but the risk is lower: for extension
        modules, the
        only cases of conflicts is when the receiver of the message
        matches the
        class of the extension module. For @Macro, any method call on
        "implicit
        this" would be matched. This draws the point of whether the
        @Macro
        stuff should also be combined with a @UseMacro local AST
        transformation,
        in order to avoid the problem of the global one.<br>
        <br>
        If we do, then definitely, the performance issue is not one
        anymore, because
        only marked code would be transformed. On the other hand, we
        introduce
        ceremony again, which would mean that we loose the benefit of
        extension
        methods being transparently visible. In the case of the pattern
        matching
        stuff, this would mean that you would have to explicitly
        annotate your
        code to enable the feature. Is it a problem? I'm not sure
        actually. Also
        it's worth noting that the global AST transformation issue is
        less of a
        problem if you have lots of macros on classpath, because a
        single transformation
        would apply them all in a single pass.<br>
        <br>
        Last but not least, my feeling is that what we need is something
        in between
        the first macro implementation and the second one. In
        particular, I would
        like to be able to write the @Macro method body using those
        macro { ...
        } blocks. It makes a lot of sense to me. Next, I wouldn't like
        to be limited
        to expressions. I think a macro should be able to produce any
        AST node.
        This implies expressions, but also statements or even full
        methods.<br>
        <br>
        I gave an example a little contrived, I admit, to Sergei, which
        is, imagine
        that I want to generate two methods with the same body, but
        accepting two
        different argument types. Then I could write a macro that
        generates the
        method:<br>
        <br>
        @Macro MethodNode createMultiply(MacroContext ctx, ClassNode
        argType) {<br>
           macro {<br>
               _argType_ multByTwo(_argType_ x) {
        2 }<br>
           }<br>
        }<br>
        <br>
        Then in a class I could write:<br>
        <br>
        class Calculator {<br>
           createMultiply int<br>
           createMultiply double<br>
        }<br>
        <br>
        Of course, this wouldn't compile because the grammar wouldn't
        allow defining
        a method in a closure (in the macro block), and it would not
        recognize
        the createMultiply calls directly in the class body, but I kind
        of like
        the idea of a macro system that just allows expanding and
        reasoning at
        the AST level anywhere, because it lets us create new language
        constructs.<br>
        <br>
        In any case, let us know what you think, what you expect from a
        macro system
        in Groovy. We have very good starting points, let's make it rock
        solid
        :-)</font>
      <br>
      <tt><font color="#8f8f8f" size="3">-- <br>
          Cédric Champeau<br>
          SpringSource - Pivotal<br>
        </font></tt><a moz-do-not-send="true"
        href="http://twitter.com/CedricChampeau" target="_blank"><tt><font
            color="blue" \
size="3"><u>http://twitter.com/CedricChampeau</u></font></tt></a><tt><font  \
color="#8f8f8f" size="3"><br>  </font></tt><a moz-do-not-send="true"
        href="http://melix.github.io/blog" target="_blank"><tt><font
            color="blue" \
size="3"><u>http://melix.github.io/blog</u></font></tt></a><tt><font  color="#8f8f8f" \
size="3"><br>  </font></tt><a moz-do-not-send="true" href="http://spring.io/"
        target="_blank"><tt><font color="blue" \
size="3"><u>http://spring.io/</u></font></tt></a><tt><font  color="#8f8f8f" size="3">
        </font></tt><a moz-do-not-send="true"
        href="http://www.gopivotal.com/" target="_blank"><tt><font
            color="blue" \
size="3"><u>http://www.gopivotal.com/</u></font></tt></a><tt><font  color="#8f8f8f" \
size="3"><br>  </font></tt>
      <br>
      <font size="3"><br>
      </font>
      <br>
      <br>
      <font size="3">-- </font>
      <br>
      <font size="3">Best regards, </font>
      <br>
      <font size="3">Sergei Egorov</font>
      <br>
      <font size="3"><br>
      </font>
      <br>
      <tt><font size="3">-- <br>
          Cédric Champeau<br>
          SpringSource - Pivotal<br>
        </font></tt><a moz-do-not-send="true"
        href="http://twitter.com/CedricChampeau"><tt><font color="blue"
            size="3"><u>http://twitter.com/CedricChampeau</u></font></tt></a><tt><font
  size="3"><br>
        </font></tt><a moz-do-not-send="true"
        href="http://melix.github.io/blog"><tt><font color="blue"
            size="3"><u>http://melix.github.io/blog</u></font></tt></a><tt><font
          size="3"><br>
        </font></tt><a moz-do-not-send="true" href="http://spring.io/"><tt><font
            color="blue" size="3"><u>http://spring.io/</u></font></tt></a><tt><font
          size="3">
        </font></tt><a moz-do-not-send="true"
        href="http://www.gopivotal.com/"><tt><font color="blue" \
size="3"><u>http://www.gopivotal.com/</u></font></tt></a><tt><font  size="3"><br>
        </font></tt>
      <br>
      <font face="sans-serif" size="2"><br>
        <br>
      </font><font face="Times New Roman" size="3"><br>
        NOTICE <i>from Ab Initio: This email (including any
          attachments) may contain
          information that is subject to confidentiality obligations or
          is legally
          privileged, and sender does not waive confidentiality or
          privilege. If
          received in error, please notify the sender, delete this
          email, and make
          no further use, disclosure, or distribution. </i></font>
    </blockquote>
    <br>
    <br>
    <pre class="moz-signature" cols="72">-- 
Cédric Champeau
SpringSource - Pivotal
<a class="moz-txt-link-freetext" \
href="http://twitter.com/CedricChampeau">http://twitter.com/CedricChampeau</a> <a \
class="moz-txt-link-freetext" \
href="http://melix.github.io/blog">http://melix.github.io/blog</a> <a \
class="moz-txt-link-freetext" href="http://spring.io/">http://spring.io/</a> <a \
class="moz-txt-link-freetext" \
href="http://www.gopivotal.com/">http://www.gopivotal.com/</a> </pre>
  </body>
</html>



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic