Caleb Clausen wrote:

> Here's the shorter of his two of his attempts to write an andand macro
> that operates like the && operator:
> 
>     called_by_name(:our_and) { |x,y|
>         if temp = x
>             y
>         else
>             temp
>         end
>     }
> 
> Not so bad in itself, but all called_by_name's must be wrapped in a
> 'with', which must get tiresome.

The use of "with" is a deliberate design choice. Rather than making 
macros global and "automagical," you state what you are using and where 
you are using it. This is somewhat akin to writing 'require 
such-and-such' in each ruby source file.

Of course, some people like magic, and if you look at Rails, the 
initializers and environment.rb file allow you to sprinkle magic 
throughout your project implicitly. My feeling when I designed rewrite 
was that that if I started with explicit "with," it would easy to build 
implicit into a project or framework later.

> The longer one is too horrible to contemplate.

> Speak for yourself ;-)

> The equivalent in RubyMacros is something like this:
> 
>   macro andand(a,b)
>     :( if temp = ^a
>             ^b
>         else
>             temp
>         end
>      )
>      #or maybe just   :( ^a && ^b )
>   end

 :( ^a && ^b ) is a little too metacircular for my taste, but I put it 
to you that rewrite allows you to define your own syntactic replacement 
using && if you want to. Now to get more specific. called_by_name is 
actually not a way of doing macros, it's a way of writing functions with 
call by name semantics.

Rewrite actually provides a facility for code rewriting, which is one 
level *above* simple unhygienic macros. A traditional unhygienic macro 
is a way of saying "when you see something that looks like a method 
call, replace it with the following code, performing substitutions here 
and here and here." Rewrite supports this as well as a number of other 
arbitrary rewriting rules.

For example, you can say "when you see foo.select { ...blah... }.map { 
...blah-blah }, replace it with a single call to .each that performs the 
selction and mapping with out iterating over the collection twice.

Now, called_by_name is actually a macro written using rewrite. So it's a 
meta-macro. I would say that gievn your example, the macro is better 
because it does not "compile" into a function call, whereas anything 
built with called_by_name will be rewritten as a function call. If what 
you want is the fastest, tightest code, use a ruby macro or use rewrite 
to directly rewrite the function call as an if statement.

If you want to compare rewrite and ruby macros more directly, there's a 
little thing I wrote called Unhygienic. It does code rewriting "by 
example." Now, I use the term "andand" to refer to 
http://andand.rubyforge.org/, so here is how to write part of that gem 
using Rewriting by example:

        Unhygienic.from(:receiver, :message, [:parameters]) {
          receiver.andand.message(parameters)
        }.to {
          lambda { |andand_temp|
            andand_temp.message(parameters) if andand_temp
          }.call(receiver)
        }

By the way, I use lambdas a lot in my rewrites to try to alleviate the 
pain of Ruby's scoping rules. If you like to live a little more 
dangerously (and the example above does), this rule can be made shorter:

        Unhygienic.from(:receiver, :message, [:parameters]) {
          receiver.andand.message(parameters)
        }.to {
          temp.message(parameters) if (temp = receiver)
        }

Both examples are longer than the macro or called_by_name definitions. 
The "from" says "here is a snippet of code where receiver, message, and 
parameters are placehilders for an expression, and expression, and a 
list of expressions. The "to" says "when you find that, replace it with 
this, plugging in the placeholders."

The idea here is that you can use any arbitrary ruby expression, not 
just something that looks like a function call. In this case, you are 
making something that looks like a method call expand into something 
else entirely.

My motivation with Rewrite was very specific: I was trying to show that 
we have alternatives to wide scale opening of core classes to implement 
DSLs and syntactic abstractions. This goal necessarily encompassed 
providing an alternative to existing idioms like #andand or 
Symbol#to_proc or #try. The goal of Ruby macros seems to be a little 
different, and thus the two gems work in different ways.

Overall, I wish Ruby macros every success and hope that people get 
excited about syntactic abstractions.
-- 
Posted via http://www.ruby-forum.com/.