Macros in Ruby

In article <41102A98.806@infofiend.com>, Ben Giddings

Jesse Jones wrote:
> For example, suppose you're writing a game and you have a lot of code
> that selects behavior based on percentages (75% of hits are normal
> blows, 20% are critical hits, and 5% kill your foe out-right for
> example). Even in a language as expressive as Ruby this is a bit
> awkward to write and not especially intentional. But with macros it can
> be written very cleanly:
>
> percent-case
> 0.75 case
> normal_hit
> end
>
> 0.20 case
> critical_hit
> end
>
> otherwise
> kill_foe
> end
> end

I'm sorry to say it, but I think you just proved Matz' point there. I
look at that, and it doesn't look like Ruby to me.

It's not Ruby. It's a little domain specific language (DSL) tailored to
a particular problem.

Even with your
explanation, I don't understand how it works, or how to modify it.

It works by mapping by mapping the DSL to the normal Ruby syntax at
compile time. The exact details aren't really important unless you want
to create a similar macro.

Is
"case" in your code the normal ruby "case" statement? It doesn't look
like it.

No, it isn't the normal case statement. It's essentially a brand-new
statement type that may be implemented in terms of case or may not be.

On the other hand, aside for this and a few other isolated cases, I
*hate* C macros, and *hate* the C preprocessor. It means that when
you're writing .c and .h files, you're not actually writing C code,
you're writing C/C-preprocessor code, and depending on who has touched
the codebase, you never quite know what's what.

Lisp and Dylan macros are far better than C macros. They're much more
powerful and safer as well. Much of the safety is because they're
hygienic macros which essentially means that names used in calls to the
macro refer to bindings that are in the scope of the macro call, and
names within the body of the macro refer to bindings in the scope of
the macro. In other words, unlike C macros, Lisp macros are not context
dependant and macros may define new variables without worrying about
conflicts with variables declared at the macro call site.

And in languages with a conventional syntax you can arrange things so
that macros come into play only in the appropiate context. For example,
a swap macro would only be used where a function call may be used. So,
unlike C, Dylan macros aren't applied blindly.

  -- Jesse

···

<bg-rubytalk@infofiend.com> wrote:

In article <41106A47.7050901@weirichhouse.org>, Jim Weirich

Jesse Jones wrote:
> percent-case
> 0.75 case
> normal_hit
> end
>
> 0.20 case
> critical_hit
> end
>
> otherwise
> kill_foe
> end
> end

I spent about 10 minutes coding this in Ruby (and it turned out to be
very similar to Joel VanderWerf's version that he posted).

Joel's solution was very cool. Certainly a lot better than any
non-macro solution I was able to come up with in a dynamic language I
was toying with.

I'm curious
what a macro version would be like. What would the implementation of
percent_case look like in Lisp or Dylan macros?

Here's a Dylan-ish macro:

macro percent-case is statement as body
    {percent-case ?cases end} =>
        {local n = random()
        if false
            0
        ?cases
        end}
    
    cases:
        {} => {}
     
        {otherwise ?:body end} =>
            {else ?body}
       
        {?percent:float-literal case ?:body end ...} =>
            {elsif (n -= ?percent) <= 0.0 ?body ...}
end

In the first line we tell the compiler that we're augmenting the
language's statement production and that the macro expansion should be
reparsed using the body production.

The code in the first set of braces is the pattern for the main-rule
(this macro only has one main-rule). ?cases refers to an aux-rule named
cases. So, the macro matches code that starts with a 'percent-case'
token, followed by something that matches the aux-rule, followed by an
'end' token.

The code in braces after the => is what the macro expands to. In this
case some simple logic plus whatever the aux rule expands to.

The aux rule has three cases which are tried in order.

1) It tries to match nothing, if this succeeds the aux rule expands to
nothing.

2) It tries to match the otherwise clause, if this succeeds the aux
rule expands to an else clause.

3) It tries to match a floating-point literal followed by 'case', a
body production, and 'end'. If we get a match the aux rule expands to
an elsif clause. The ... means the aux rule is recursively invoked
again so we essentially iterate until we run out of cases.

Note that the macro defines an 'n" local variable. Because macros are
hygienic any references to n within the body of the macro refer to that
n even if the macro call site has a variable named n in scope.

  -- Jesse

···

<jim@weirichhouse.org> wrote:

In article <9e7db91104080322005735a859@mail.gmail.com>, Austin Ziegler

> percent-case
> 0.75 case
> normal_hit
> end
>
> 0.20 case
> critical_hit
> end
>
> otherwise
> kill_foe
> end
> end

I'm sorry, but I don't see how this is more readable than:

  case hit_roll
    when (0.0 .. 0.75)
      normal_hit
    when (0.75 .. 0.95)
      critical_hit
    else
      kill_foe
    end
  end

A macro (or some clever code like Joel's) is better in two ways:

1) It's much easier to glance at numbers like 0.75 and 0.20 and figure
out the relative weighting. For me at least, it's a fair amount harder
to subtract two sets of numbers and compare them. Of course, you could
add comments listing the percentages, but it's always preferable to
rewrite the code so that it doesn't need such comments.

2) Adding new cases is harder if you have to deal with ranges. Not a
lot harder to be sure, but somewhat tedious.

Also note that this wasn't intended to be the last word in the utility
of macros. It was merely one of the simpler app specific examples I
could think of.

  -- Jesse

···

<halostatue@gmail.com> wrote:

On Wed, 4 Aug 2004 08:26:32 +0900, Jesse Jones <jesjones@mindspring.com> > wrote:

Or you could even do it like this, which looks (to me) even nicer than the macro solution :slight_smile:

class PercentCase
   def initialize
     @v = rand(100)
   end
  
   def test(o)
     @v -= o
     @v <= 0
   end
end

class Integer
   alias_method :percentCase, :===
   def ===(o)
     if o.is_a? PercentCase
       o.test self
     else
       percentCase o
     end
   end
end

10.times do
   case PercentCase.new
   when 75
     puts 'normal_hit'
   when 20
     puts 'critical_hit'
   else
     puts 'kill_foe'
   end
end

···

On Wed, 4 Aug 2004 09:12:41 +0900, Joel VanderWerf <vjoel@PATH.Berkeley.EDU> wrote:

Jesse Jones wrote:

For example, suppose you're writing a game and you have a lot of code
that selects behavior based on percentages (75% of hits are normal
blows, 20% are critical hits, and 5% kill your foe out-right for
example). Even in a language as expressive as Ruby this is a bit
awkward to write and not especially intentional. But with macros it can
be written very cleanly:
percent-case
   0.75 case
      normal_hit
   end
    0.20 case
      critical_hit
   end
    otherwise
      kill_foe
   end
end

It's not really that hard to do something like this in ruby, but it is a little less efficient than it would be with macros.

[...]

--
exoticorn/farbrausch

In article <410F187F.1070602@neurogami.com>,

···

James Britt <jamesUNDERBARb@neurogami.com> wrote:

Phil Tomson wrote:

In article <410EC9A6.5010107@neurogami.com>,
James Britt <jamesUNDERBARb@neurogami.com> wrote:

..

But, even supposing one could, I believe the Darwinian forces in a
development community would prevent abuse of macros from becoming prevalent.

Agreed.

While Matz may have 'banned' macros from the core language, that doesn't
mean that if someone comes up with a way to do LISP-like macros
implemented in an external module, (that could be downloaded
from the RAA for example) that Matz would ban the module. He probably
would never consider bundling it with the Ruby distribution, of course,
but that doesn't mean it would be 'banned'.

If such a module did ever become available those who would be interested
in such things would use it and those who were not interested would
ignore it.

It's kind of like how the static typing advocates occasionally come up
with some code for emulating static typing in Ruby (and you can probably
find some on the RAA) while most of us think that such things are
ill-advised, no one is stopping the advocates of such things from using
it.

Oh, nice move. Associating Lisp-style macros with static typing.

I curse you, Phil Tomson!

Ohhh no!! Another 7 years! :wink:

Actually, I find the idea of Lisp-style macros interesting, while I find
the idea of static typing in Ruby just plain bad... but YMMV.

Phil

In article <030820041658374069%jesjones@mindspring.com>,

In article <cemm7i0126g@enews2.newsguy.com>, Phil Tomson

While Matz may have 'banned' macros from the core language, that doesn't
mean that if someone comes up with a way to do LISP-like macros
implemented in an external module, (that could be downloaded
from the RAA for example) that Matz would ban the module. He probably
would never consider bundling it with the Ruby distribution, of course,
but that doesn't mean it would be 'banned'.

This seems hard to do well. A good macro system really needs to be
integrated into the language. If not, you wind up with abortions like
the C/C++ macro system which is both dangerous to use and
under-powered.

It might be possible to do with an open compiler (ie one that provided
hooks to allow third-party components to affect its behavior). I tend
to be a bit suspicious of open compilers though. They seem to either
lock users into particular implementations or significantly constrain
compiler implementations. I'll have to think about it some more, but it
seems like adding macros wouldn't be all that much more difficult to
implement than opening the parser up.

It's kind of like how the static typing advocates occasionally come up
with some code for emulating static typing in Ruby (and you can probably
find some on the RAA) while most of us think that such things are
ill-advised, no one is stopping the advocates of such things from using
it.

I don't see the connection. Static typing runs counter to the whole
concept of typing in Ruby. Macros, on the other hand, are a completely
orthogonal concept and, if anything, fit well into the Ruby philosophy
of providing a flexible and expressive language.

Read my later post. I was only using that debate as an example...

There is a camp of folks who think that Ruby needs to emulate
static-typing in some cases. There is another camp that thinks this is a
bad idea. Similarly, there is a camp that says that macros would be
useful (or at least interesting to explore - that's kind of where I'm at
since I've never used LISP macros) and there is another camp (which Matz
is in) that says that macros are just plain bad. Since Matz is in the
latter camp you're not likely to see macros included in Ruby
'out-of-the-box', but if you can some up with an addon to do macros (if
it's possible)...

I wasn't trying to tie static typing and macros together.

Phil

···

Jesse Jones <jesjones@mindspring.com> wrote:

<ptkwt@aracnet.com> wrote:

Just some minor remark...

"Joel VanderWerf" <vjoel@PATH.Berkeley.EDU> schrieb im Newsbeitrag
news:41103008.7030107@path.berkeley.edu...

Jesse Jones wrote:
>>Your statement implies that Ruby blocks are
>>equivalent to LISP closures, which is untrue.
>
>
> As far as I can tell Lisp lambda functions (ie closures) do everything
> that Ruby blocks and proc objects do but with cleaner semantics and
> fewer artifical distinctions.

What are some of the differences? I've been away from lisp for a

while....

>>>>From what I can tell macros offer three benefits: 1) They allow you

to

>>>extend the syntax of the language to directly support your problem
>>>domain. For example, if you work with finite-state machines you can
>>>write a macro that allows you to declaratively define FSMs.
>>
>>I bet it's easy to declaritively define FSMs in Ruby.
>
>
> I'm not so sure, I experimented with defining FSMs in a dynamic
> language with good support for anonymous functions/closures and the
> macro based solution was a whole lot nicer to use.

I've found ruby blocks to be fairly good for defining declarative
constructs. For example, I based the syntax for a declarative language
for hybrid automata (~ FSMs + ODEs) on this technique. Here's a sample:

class Vehicle < Component
   state :SpeedUp, :SlowDown

   default do
     self.x = 0
     self.xDot = 20
     start SlowDown
   end

You could get rid of the "self" if you defined a method that receives a
hash along the lines of:

   default do

     values( :x => 0, :xDot => 20 )
     start SlowDown
   end

Or even remove the values setting from the block.

Since I don't know the inner workings I don't know whether there are other
factors that prevent this solution. Just an idea.

   setup do
     @timer = create(Timer)
   end

   flow SpeedUp, SlowDown do
     diff "xDot' = xDDot"
     diff "x' = xDot"
   end

   flow SpeedUp do
     alg "xDDot = 3"
   end

   flow SlowDown do
     alg "xDDot = -3"
   end

   transition SpeedUp => SlowDown, SlowDown => SpeedUp do
     guard {@timer.tick}
     action {puts "Tick!"}
   end
end

(The parsing of all these blocks--using instance_eval plus manual
parsing of the differential/algebraic equations--happens at load time,
then there is a compile stage which generates a dynamic lib and loads
it, and at run time it's mostly native code executing, with an
occasional call to a ruby proc or method.)

So you create C code and compile it?

The one respect in which ruby was less than perfectly suitable to this
syntactical problem is having to use "self.x = ..." all the time, but
there are good reasons for that in the bigger picture.

See above.

Regards

    robert

In article <41103008.7030107@path.berkeley.edu>, Joel VanderWerf

Jesse Jones wrote:
>>Your statement implies that Ruby blocks are
>>equivalent to LISP closures, which is untrue.
>
>
> As far as I can tell Lisp lambda functions (ie closures) do everything
> that Ruby blocks and proc objects do but with cleaner semantics and
> fewer artifical distinctions.

What are some of the differences? I've been away from lisp for a while....

Between Ruby and Lisp? To tell the truth I'm not entirely sure. The
pickaxe book does a lousy job explaining the differences between blocks
and proc objects. I'm still not sure why Ruby needs two concepts when
Lisp and other languages get by with one. I also don't know why Ruby
uses that weird yield syntax.

> I'm not so sure, I experimented with defining FSMs in a dynamic
> language with good support for anonymous functions/closures and the
> macro based solution was a whole lot nicer to use.

I've found ruby blocks to be fairly good for defining declarative
constructs. For example, I based the syntax for a declarative language
for hybrid automata (~ FSMs + ODEs) on this technique. Here's a sample:

Very nice Joel. Macro's wouldn't seem to be a huge improvement except
that you could inline code instead of turning everything into blocks.

Hm? Blocks can be used to defer evaluation, using the &block or Proc.new
constructs. Or do you mean something else?

I meant just what I said: that macros allow you to control the order of
evaluation of expressions. Although you're probably right that I should
have pointed out that blocks allow you to do the same.

  -- Jesse

···

<vjoel@PATH.Berkeley.EDU> wrote:

Hmm. I disagree. I mean, it's better to deal with code like Joel's (or
my Attacker class that I presented, which even makes sure you can't go
over 100%), because then you've treated the cases as closures and
objectified the whole thing, so that you don't have to do the numbers,
but basically (0 .. 75) says very clearly that you'll accept any value
in that range. It's harder to be dynamic, but you'll note that my
Attacker class (the second possibility in the email to which you
responded) makes that easy and still uses the range comparison.

I don't think that a domain-specific language is needed for that case.
The only situation I can think of that came up recently was the one
where someone wanted to introduce the a new operator ":="; that could
be handled with a domain-specific language with ease.

-austin

···

On Wed, 4 Aug 2004 21:11:30 +0900, Jesse Jones <jesjones@mindspring.com> wrote:

In article <9e7db91104080322005735a859@mail.gmail.com>, Austin Ziegler
<halostatue@gmail.com> wrote:
> On Wed, 4 Aug 2004 08:26:32 +0900, Jesse Jones <jesjones@mindspring.com> > > wrote:
> > percent-case
> > 0.75 case
> > normal_hit
> > end
> >
> > 0.20 case
> > critical_hit
> > end
> >
> > otherwise
> > kill_foe
> > end
> > end
> I'm sorry, but I don't see how this is more readable than:
>
> case hit_roll
> when (0.0 .. 0.75)
> normal_hit
> when (0.75 .. 0.95)
> critical_hit
> else
> kill_foe
> end
> end
A macro (or some clever code like Joel's) is better in two ways:

1) It's much easier to glance at numbers like 0.75 and 0.20 and figure
out the relative weighting. For me at least, it's a fair amount harder
to subtract two sets of numbers and compare them. Of course, you could
add comments listing the percentages, but it's always preferable to
rewrite the code so that it doesn't need such comments.

--
Austin Ziegler * halostatue@gmail.com
               * Alternate: austin@halostatue.ca

Jesse Jones wrote:

In article <41102A98.806@infofiend.com>, Ben Giddings

I'm sorry to say it, but I think you just proved Matz' point there. I look at that, and it doesn't look like Ruby to me.

It's not Ruby. It's a little domain specific language (DSL) tailored to
a particular problem.

I don't have an opinion on macros per se, but DSLs are (in my opinion) a poor application for macros. To paraphrase Dennis Ritchie, if you want racc, you know where to find it.

I'm a big fan of DSLs, but I like to build them up from the grammar.

Steve

···

<bg-rubytalk@infofiend.com> wrote:

Jesse Jones wrote:

percent-case
0.75 case
   normal_hit
end

0.20 case
   critical_hit
end

otherwise
   kill_foe
end
end

I'm sorry, but I don't see how this is more readable than:

case hit_roll
   when (0.0 .. 0.75)
     normal_hit
   when (0.75 .. 0.95)
     critical_hit
   else
     kill_foe
   end
end

A macro (or some clever code like Joel's) is better in two ways:

1) It's much easier to glance at numbers like 0.75 and 0.20 and figure
out the relative weighting. For me at least, it's a fair amount harder
to subtract two sets of numbers and compare them. Of course, you could
add comments listing the percentages, but it's always preferable to
rewrite the code so that it doesn't need such comments.

I don't think you're right on this point. In the case that was
presented:

> 0.75 case
> normal_hit
> end

Does this mean 0.75 and above, or 0.75 and below? You won't know
this unless you look up the macro's definition. Here, however:

> when (0.0 .. 0.75)
> normal_hit

I don't think you can be confused on that point.

The macro version has made the code much less clear in my mind, which is
precisely the argument against macros in ruby.

···

--
Rando Christensen
<eyez@illuzionz.org>

Jesse Jones wrote:
>>Your statement implies that Ruby blocks are
>>equivalent to LISP closures, which is untrue.
>
> As far as I can tell Lisp lambda functions (ie closures) do everything
> that Ruby blocks and proc objects do but with cleaner semantics and
> fewer artifical distinctions.

Lisp lambda functions *do* do everything that Ruby blocks do. But
doing is not the same as being. I wrote that they are not equivalent.
The difference is syntax. It's an artifical distinction that works
tremendously well in practice at expressing the solution in code.

What are some of the differences? I've been away from lisp for a while....

Between Ruby and Lisp? To tell the truth I'm not entirely sure. The
pickaxe book does a lousy job explaining the differences between blocks
and proc objects. I'm still not sure why Ruby needs two concepts when
Lisp and other languages get by with one. I also don't know why Ruby
uses that weird yield syntax.

On the one hand you advocate macros to make syntax more expressive; on
the other you advocate rolling everything back into anonymous
functions with no visual distinctions. *shrug*

Gavin

···

On Wednesday, August 4, 2004, 10:41:43 PM, Jesse wrote:

In article <411108CE.5060805@ieee.org>, Steven Jenkins

Jesse Jones wrote:
> In article <41102A98.806@infofiend.com>, Ben Giddings
>>I'm sorry to say it, but I think you just proved Matz' point there. I
>>look at that, and it doesn't look like Ruby to me.
>
> It's not Ruby. It's a little domain specific language (DSL) tailored to
> a particular problem.

I don't have an opinion on macros per se, but DSLs are (in my opinion) a
poor application for macros. To paraphrase Dennis Ritchie, if you want
racc, you know where to find it.

I'm a big fan of DSLs, but I like to build them up from the grammar.

Which is *exactly* what Dylan macros do. When you define a new Dylan
macro you're directly extending Dylan's grammar. But, unlike racc, your
domain specific language is integrated into the base language and you
can use the compiler to handle lexing and parsing.

Here's a Scheme paper that contrasts the traditional approach to DSLs
with a macro based one: <http://www.ai.mit.edu/people/shivers/ll.ps&gt;\.

  -- Jesse

···

<steven.jenkins@ieee.org> wrote:

> <bg-rubytalk@infofiend.com> wrote:

Rando Christensen <eyez@illuzionz.org> writes:

The macro version has made the code much less clear in my mind, which is
precisely the argument against macros in ruby.

Actually, the example Jesse gave was probably bad. A macro, like any
other language construct, can be created to enhance clarity or
obfucate. Thus, one should not make a hasty judgement based on that
one example.

How about this example (which I hope is a better example of
easy-with-macro,-hard-(impossible?)-without):

Suppose we want to do self-documenting methods (not source file),
similar to docstring in emacs:

An implementation with macro would look something like:

def foo(arg)
    "This method will return <code>arg</code>"
    arg
end

Sure, you can implement this without macro (trivial implementation):

DOCSTRINGS={}
def def_with_docstring(klazz, method_name, docstring, arg_spec, body)
  id = "#{klazz.to_s}##{method_name}"
  DOCSTRINGS[id] = docstring
  klazz.module_eval(%{def #{method_name}(#{arg_spec})
                           #{body}
                      end}, __FILE__, 9999) # wish that there isn't
                                            # anything on line 9999.
end

def_with_docstring(Object, "foo", "returns arg", "arg", "arg")
  
Object.new.foo("hi") # => "hi"

Yes, I am aware you can do more sophisticated implementation so you
can make the above nicer. Yet, as nice as it will be, it won't be as
simple as the example with macro; there will be quirkiness caused by
the language syntax.

For example, rake has this in its documentation: "NOTE: Because of a
quirk in Ruby syntax, parenthesis are required on rule when the first
argument is a regular expression."

Another example: I am not even sure you can turn the above example to
take lambdas as the body. Being able to take lambdas would be nice as
you can take advantage of your editor's syntax highlighting and
auto-indent.

YS.

In article <41115242.1020602@illuzionz.org>, Rando Christensen

I don't think you're right on this point. In the case that was
presented:

> 0.75 case
> normal_hit
> end

Does this mean 0.75 and above, or 0.75 and below? You won't know
this unless you look up the macro's definition.

The macro is called percent-case for a reason. "0.75 case" means that
case will be taken 75% of the time. It should be possible to change the
macro so that it would support things like "75% case" which might be
better if you want a macro that may be used in apps where its usage
would be uncommon.

The macro version has made the code much less clear in my mind, which is
precisely the argument against macros in ruby.

I don't see that. In any non-trivial program there's plenty of code
that isn't perfectly intentional. I'm sure you don't consider method
calls a bad thing because it's often not clear exactly what they do.
Macros are no different: they can make code clearer than hand-coding
the solution, but if you're not familiar with the app you'll probably
have to familiarize yourself with the commonly used macros just as you
would do with the commonly used classes.

  -- Jesse

···

<eyez@illuzionz.org> wrote:

In article <138135881306.20040805010035@soyabean.com.au>, Gavin

> Between Ruby and Lisp? To tell the truth I'm not entirely sure. The
> pickaxe book does a lousy job explaining the differences between blocks
> and proc objects. I'm still not sure why Ruby needs two concepts when
> Lisp and other languages get by with one. I also don't know why Ruby
> uses that weird yield syntax.

On the one hand you advocate macros to make syntax more expressive; on
the other you advocate rolling everything back into anonymous
functions with no visual distinctions. *shrug*

Well, what are the differences between blocks and proc objects? As far
as I can tell the only difference is that proc objects are explicitly
declared in method argument lists and are first class objects. Blocks,
on the other hand, are not listed in the method list (unless you use
&block to create a proc) and called using yield.

How does that make the language more expressive? Implicitly passing
arguments seems actively bad and using "yield lhs rhs" seems worse than
using "compare.call lhs rhs".

  -- Jesse

···

Sinclair <gsinclair@soyabean.com.au> wrote:

On Wednesday, August 4, 2004, 10:41:43 PM, Jesse wrote:

"Yohanes Santoso" <ysantoso-rubytalk@dessyku.is-a-geek.org> schrieb im
Newsbeitrag news:877jseplp6.fsf@dessyku.is-a-geek.org...

Rando Christensen <eyez@illuzionz.org> writes:

> The macro version has made the code much less clear in my mind, which

is

> precisely the argument against macros in ruby.

Actually, the example Jesse gave was probably bad. A macro, like any
other language construct, can be created to enhance clarity or
obfucate. Thus, one should not make a hasty judgement based on that
one example.

How about this example (which I hope is a better example of
easy-with-macro,-hard-(impossible?)-without):

Suppose we want to do self-documenting methods (not source file),
similar to docstring in emacs:

An implementation with macro would look something like:

def foo(arg)
    "This method will return <code>arg</code>"
    arg
end

Sure, you can implement this without macro (trivial implementation):

DOCSTRINGS={}
def def_with_docstring(klazz, method_name, docstring, arg_spec, body)
  id = "#{klazz.to_s}##{method_name}"
  DOCSTRINGS[id] = docstring
  klazz.module_eval(%{def #{method_name}(#{arg_spec})
                           #{body}
                      end}, __FILE__, 9999) # wish that there isn't
                                            # anything on line 9999.
end

This will print wrong file names for all methods not defined in that file.
I'd prefer something like this:

module DocMix
  def doc(item, text)
    (@docs ||= {})[item.to_s] = "#{item} defined in #{caller[0]}: #{text}"
  end

  def get_doc(item)
     @docs ? @docs[item.to_s] : nil
  end
end

class Class ; include DocMix end
class Module ; include DocMix end

class Foo
  doc :bar, "Method that prints hallo 'name'"
  def bar(name)
    puts "hallo #{name}"
  end
end

puts Foo.get_doc( :bar )

module Test
  doc :"Test.bar", "Method that prints hallo 'name'"
  def self.bar(name)
    puts "hallo #{name}"
  end
end

puts Test.get_doc( :"Test.bar" )

Of course one could easily add argument names etc. Personally I never
needed Macros until now and I've yet to see a use case where I would
really need them.

def_with_docstring(Object, "foo", "returns arg", "arg", "arg")

Object.new.foo("hi") # => "hi"

Yes, I am aware you can do more sophisticated implementation so you
can make the above nicer. Yet, as nice as it will be, it won't be as
simple as the example with macro; there will be quirkiness caused by
the language syntax.

For example, rake has this in its documentation: "NOTE: Because of a
quirk in Ruby syntax, parenthesis are required on rule when the first
argument is a regular expression."

Another example: I am not even sure you can turn the above example to
take lambdas as the body. Being able to take lambdas would be nice as
you can take advantage of your editor's syntax highlighting and
auto-indent.

You could do that. But you couldn't define methods that receive a body as
lamba that way. That's a restriction of define_method which you would
have to use in this case.

Regards

    robert

def_with_docstring(Object, "foo", "returns arg", "arg", "arg")
  
Object.new.foo("hi") # => "hi"

Yes, I am aware you can do more sophisticated implementation so you
can make the above nicer. Yet, as nice as it will be, it won't be as
simple as the example with macro; there will be quirkiness caused by
the language syntax.

not that much, did you see the MetaTags system or the various
implementations of docstrings?

Something on the lines of:

doc 'this things does foo'
def foo
...
end

is quite trivial to do.

For example, rake has this in its documentation: "NOTE: Because of a
quirk in Ruby syntax, parenthesis are required on rule when the first
argument is a regular expression."

IIRC this is related to bison not being good enough :slight_smile:

Hi --

Rando Christensen <eyez@illuzionz.org> writes:

> The macro version has made the code much less clear in my mind, which is
> precisely the argument against macros in ruby.

Actually, the example Jesse gave was probably bad. A macro, like any
other language construct, can be created to enhance clarity or
obfucate. Thus, one should not make a hasty judgement based on that
one example.

How about this example (which I hope is a better example of
easy-with-macro,-hard-(impossible?)-without):

Suppose we want to do self-documenting methods (not source file),
similar to docstring in emacs:

An implementation with macro would look something like:

def foo(arg)
    "This method will return <code>arg</code>"
    arg
end

You can already do that, if you don't mind a warning with -w :slight_smile: But
assuming you intend a macro to let you do things that are otherwise
illegal syntax, that's where the problem arises of having everyone's
code, potentially, look and act different, and, as others have said,
just not to look like Ruby. (Unless we define "Ruby" as "a macro
language in which any syntax is possible", but I'd rather not :slight_smile:

David

···

On Thu, 5 Aug 2004, Yohanes Santoso wrote:

--
David A. Black
dblack@wobblini.net

Yohanes Santoso wrote...

and this is what the doc has to say about the '!Class' tag:

  !Class - A string indicating the fully-qualified class name. This
            is a required field.

Robert's example is about similar to what MetaTags does. Thus, they
both make one to repeat one self; you have to say: "this docstring is
for this method of this class", even if the information is available
nearby. I think this counts as quirkiness.

Actually, you don't:

# utterly broken but shows the concept:

[nickel@UltimaThule nickel]$ irb --simple-prompt

def doc str
@is_test=str
end

=> nil

class Module
Docs=Hash.new
def method_added(id)
  Docs[id]=@is_test if @is_test
end
end

=> nil

class Foo
doc "this speaks"
def meow
  "meoww"
end
end

=> nil

Module::Docs[:meow]

=> "this speaks"

module M
def foo
end
doc "yuppy"
def baz
  'naia'
end
end

=> nil

Module::Docs[:baz]

=> "yuppy"

anyway, I agree this is really far from perfect :slight_smile: