Macros in Ruby

Hello everyone,

one of the features of the LISP family of languages that is missing from
Ruby are macros. I think they are useful on a lot of occasions so
I would like to see Ruby support macros in the future.

However i think it is quite easy to emulate some form of macro functionality in Ruby. Here is some simple code:

macros.rb:

···

----------

$__macros__ = {}
$__required__ = {}

module Kernel

alias_method :old_require, :require
def require(path)
  return if $__required__[path]
  
  source = open(path) { |f|
    f.sysread(f.stat().size())
  }
  
  # parse macro
  source.gsub!(/defmacro\s*\/(.*?)\/\s(.*?)endmacro/m) {
    $__macros__[Regexp.new($1)] = $2 ; ""
  }
  
  # expand macros
  $__macros__.each { |match, replace|
    source.gsub!(match, replace)
  }
  
  $__required__[path] = true

  eval(source)
end

end

require "test1.rb"
require "test2.rb"

test1.rb:
---------

defmacro /my_macro\((.*)\)/
  begin
    my_function(\1)
  rescue => ex
    puts ex
  end
endmacro

# php style foreach
defmacro /foreach\s*\((.*)\s*as(.*)\)/
  for \2 in \1
endmacro

def my_function(str)
  puts str
end

class TestClass
  def another_test
    words = %w{ simple test }
    foreach(words as word)
      puts k
    end
  end
end

test2.rb:
---------

value = "Hello World!"
my_macro(value)

numbers = [1, 2, 3, 4]

foreach (numbers as i)
  puts i
end

a = TestClass.new
a.another_test()

Once again i was suprised to find out that Ruby is so powerful!

However I would like to hear your opinion on this code. Is there any problem I have overlooked? Is there a better implementation? Could this be better designed?

If anyone finds it usefull I could create a small package with doc+examples and upload it to RAA.

have fun,
George Moschovitis

--
www.navel.gr
www.joy.gr

* George Moschovitis <gm@navel.gr> [2004-08-02 18:16:35 +0900]:

Hello everyone,

one of the features of the LISP family of languages that is missing from
Ruby are macros. I think they are useful on a lot of occasions so
I would like to see Ruby support macros in the future.

However i think it is quite easy to emulate some form of macro
functionality in Ruby. Here is some simple code:

I've heard Matz say that Ruby will not support macros.
They are too easily abused and can mutate the language.
Besides, you can achieve the same powerful affect using
blocks.

Jim

George Moschovitis wrote:

Hello everyone,

one of the features of the LISP family of languages that is missing from
Ruby are macros. I think they are useful on a lot of occasions so
I would like to see Ruby support macros in the future.

What you have defined are more like C macros, rather than LISP macros, which are hygienic (they operate at the level of syntactic elements, rather than characters).

In article <cel0la$2sto$1@ulysses.noc.ntua.gr>,

Hello everyone,

one of the features of the LISP family of languages that is missing from
Ruby are macros. I think they are useful on a lot of occasions so
I would like to see Ruby support macros in the future.

<code snipped>

Once again i was suprised to find out that Ruby is so powerful!

However I would like to hear your opinion on this code. Is there any
problem I have overlooked? Is there a better implementation? Could this
be better designed?

If anyone finds it usefull I could create a small package with
doc+examples and upload it to RAA.

have fun,
George Moschovitis

I've never used Lisp so I'm not too familiar with Lisp macros and I know
that Matz isn't too fond of macros. However, I can't help feeling that
you've created something quite cool here and I'd certainly like to see
more.

Please do post something on the RAA! Maybe you could put it up on
rubyforge?

Phil

···

George Moschovitis <gm@navel.gr> wrote:

In article <cel0la$2sto$1@ulysses.noc.ntua.gr>,

Hello everyone,

one of the features of the LISP family of languages that is missing from
Ruby are macros. I think they are useful on a lot of occasions so
I would like to see Ruby support macros in the future.

However i think it is quite easy to emulate some form of macro
functionality in Ruby. Here is some simple code:

macros.rb:
----------

$__macros__ = {}
$__required__ = {}

module Kernel

alias_method :old_require, :require
def require(path)
return if $__required__[path]

source = open(path) { |f|
  f.sysread(f.stat().size())
}

# parse macro
source.gsub!(/defmacro\s*\/(.*?)\/\s(.*?)endmacro/m) {
  $__macros__[Regexp.new($1)] = $2 ; ""
}

# expand macros
$__macros__.each { |match, replace|
  source.gsub!(match, replace)
}

$__required__[path] = true

eval(source)
end

end

require "test1.rb"
require "test2.rb"

test1.rb:
---------

defmacro /my_macro\((.*)\)/
begin
  my_function(\1)
rescue => ex
  puts ex
end
endmacro

# php style foreach
defmacro /foreach\s*\((.*)\s*as(.*)\)/
for \2 in \1
endmacro

def my_function(str)
puts str
end

class TestClass
def another_test
  words = %w{ simple test }
  foreach(words as word)
    puts k
  end
end
end

test2.rb:
---------

value = "Hello World!"
my_macro(value)

numbers = [1, 2, 3, 4]

foreach (numbers as i)
puts i
end

a = TestClass.new
a.another_test()

Once again i was suprised to find out that Ruby is so powerful!

However I would like to hear your opinion on this code. Is there any
problem I have overlooked? Is there a better implementation? Could this
be better designed?

Another comment: maybe instead of redefining 'require' you should just
have another method on kernel, something like 'load_macro' or
'require_macro'? This would make it clear that you are loading code which
contains macros. Perhaps even the file extension should be different for
these files to avoid confusion (*.rbm?).

Also, right now you can only define these macros in files that get
required, maybe you should also allow for the definition of macros in
strings or here-docs?

Phil

···

George Moschovitis <gm@navel.gr> wrote:

I have to say that, for me, Ruby procs work just fine in place of macros,
except if I could change one thing, it would be this:

The ability to modify the binding in which procs run.

Sometimes I really wish I could make a call in a method or class definition,
and have that proc run in the context where I call it, instead of where it's
defined. Like so:

module ModOne
  @var = "one"

  TestProc = Proc.new do
    @var
  end
end

module ModTwo
  @var = "two"

  ModOne::TestProc.call #=> "two"
end

...perhaps making a new class named "Macro" which is essentially Proc, but
which executes in the current binding instead of the binding where it was
created.

  Sean O'Dell

···

On Monday 02 August 2004 02:16, George Moschovitis wrote:

Hello everyone,

one of the features of the LISP family of languages that is missing from
Ruby are macros. I think they are useful on a lot of occasions so
I would like to see Ruby support macros in the future.

I've heard Matz say that Ruby will not support macros.
They are too easily abused and can mutate the language.

I 've heard that, but macros ARE usefull. Take a look
at www.paulgraham.com for example.

Besides, you can achieve the same powerful affect using
blocks.

How can i use blocks to emulate macros ? I cannot understand
that.

George

···

--
www.navel.gr
www.joy.gr

Joel VanderWerf wrote:

What you have defined are more like C macros, rather than LISP macros, which are hygienic (they operate at the level of syntactic elements, rather than characters).

You are of course right. But you can do still usefull things. And I think it can be improved. Any ideas are welcome. Even better would be support for macros in Ruby 1.9 :slight_smile:

George.

···

--
www.navel.gr
www.joy.gr

Joel VanderWerf wrote:

George Moschovitis wrote:

Hello everyone,

one of the features of the LISP family of languages that is missing from
Ruby are macros. I think they are useful on a lot of occasions so
I would like to see Ruby support macros in the future.

What you have defined are more like C macros, rather than LISP macros, which are hygienic (they operate at the level of syntactic elements, rather than characters).

Would Ruby macros, in the Lisp sense, have to manipulate the AST?

And a question (ideally) for Matz, but comments from anyone else are of course welcome:

Would true macros in Ruby be more prone to abuse than they are in Lisp?

Is there something different about Ruby such that what (supposedly) works to such acclaim in Lisp would be inappropriate in Ruby?

Thanks,

James

I've sometimes found myself wanting macros for things that *cannot* be
done with blocks currently; however, in most cases they could have been
accomplished easily had the often proposed extensions to Binding and
Kernel#caller been implemented.

···

On Tue, Aug 03, 2004 at 12:45:02AM +0900, jim@freeze.org wrote:

I've heard Matz say that Ruby will not support macros.
They are too easily abused and can mutate the language.
Besides, you can achieve the same powerful affect using
blocks.

--
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

* George Moschovitis <gm@navel.gr> [2004-08-02 18:16:35 +0900]:

Hello everyone,

one of the features of the LISP family of languages that is missing from
Ruby are macros. I think they are useful on a lot of occasions so
I would like to see Ruby support macros in the future.

However i think it is quite easy to emulate some form of macro
functionality in Ruby. Here is some simple code:

I've heard Matz say that Ruby will not support macros.

True, Matz has said that. But if we can do something Macro-like with a
module (as George has shown) then it's optional.

They are too easily abused and can mutate the language.
Besides, you can achieve the same powerful affect using
blocks.

Not quite. Notice that George introduced totally new 'syntax' using his
'macros' - you can't do that with blocks.

Phil

···

In article <20040802154500.GB67163@freeze.org>, <jim@freeze.org> wrote:

Hello jim,

However i think it is quite easy to emulate some form of macro
functionality in Ruby. Here is some simple code:

I've heard Matz say that Ruby will not support macros.

And i hope that he never changes his opinion at this topic.

They are too easily abused and can mutate the language.

They easily make code much more unreadable. I think that languages
like D, C# etc now exactly why they don't want something like macros.

As said before lisp is different because of the general S-Expression
style of this language.

I remember an asian saying about thinks like this:

"Der Kluge fügt jeden Tag etwas hinzu,
Der Weise entfernt jeden Tag etwas".

Translated to english it is something like:

"The clever man adds something every day,
The wise man removes something every day".

···

--
Best regards, emailto: scholz at scriptolutions dot com
Lothar Scholz http://www.ruby-ide.com
CTO Scriptolutions Ruby, PHP, Python IDE 's

Another comment: maybe instead of redefining 'require' you should just

....

strings or here-docs?

Hello Phil,

thanks for your comments. I 'll work on the code a bit and post a new
version. I 'll try to include your requests. I agree with you that
macros are usefull. For example i use them in a coll localization scheme, or even for loging (using this simple macro implementation,
I can fully strip the logging/profiling code, much better than using
a block, and more flexible than using AOP techinques).

Anyway it would be nice to hear more ideas, comments!

regards,
George Moschovitis

···

--
www.navel.gr
www.joy.gr

module ModOne
  @var = "one"

  TestProc = Proc.new do
    @var
  end
end

module ModTwo
  @var = "two"

  ModOne::TestProc.call #=> "two"
end

In this particular case, it can be solved with

batsman@tux-chan:/tmp$ cat hfdh.rb
module ModOne
    @var = "one"

    TestProc = Proc.new do
        @var
    end
end

module ModTwo
    @var = "two"

    p instance_eval(&ModOne::TestProc) #=> "two"
end

batsman@tux-chan:/tmp$ ruby hfdh.rb
"two"

...perhaps making a new class named "Macro" which is essentially Proc, but
which executes in the current binding instead of the binding where it was
created.

I do agree on the fact that better control of the bindings (as often
proposed in the past) would make several of the things people would want
to do with macros possible without further language modifications.

···

On Fri, Aug 06, 2004 at 01:38:08AM +0900, Sean O'Dell wrote:

--
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

manipulated as a simple tree of cons cells; Ruby code, even if a
high-level programmatic interface existed to the AST, has a much
richer syntax, and therefore more complex structure.

Also, as has been mentioned, Ruby largely replaces macros with blocks
-- they allow delayed evaluation, specialized iteration and
pre/post-condition checks, etc. Many of the common macros you'll see
in Lisp are things like this:

(with-open-file "foo.dat" my-file (case (read-char my-file) ...))

[my apologies for the weird function names; it's been a couple of
years since I was actively developing any Lisp code]

Obviously, that example is quite handily supported by the more
Ruby-esque example below:

open("foo.dat") {|my_file| case my_file.getc ...}

Personally, I think macros could be an interesting tool for very
special cases, but they're not an essential feature for 90% of
developers. Now, exposing the AST with a high-level API could have
other benefits: code analysis and optimization, JIT compilers,
documentation generators, etc.

Lennon

···

On Tue, 3 Aug 2004 02:29:34 +0900, James Britt <jamesunderbarb@neurogami.com> wrote:

Is there something different about Ruby such that what (supposedly)
works to such acclaim in Lisp would be inappropriate in Ruby?

A: S-expressions, or the lack thereof in Ruby. Lisp code can always be

In article <20040802182747.GA7661@student.ei.uni-stuttgart.de>,

···

Mauricio Fernández <batsman.geo@yahoo.com> wrote:

On Tue, Aug 03, 2004 at 12:45:02AM +0900, jim@freeze.org wrote:

I've heard Matz say that Ruby will not support macros.
They are too easily abused and can mutate the language.
Besides, you can achieve the same powerful affect using
blocks.

I've sometimes found myself wanting macros for things that *cannot* be
done with blocks currently; however, in most cases they could have been
accomplished easily had the often proposed extensions to Binding and
Kernel#caller been implemented.

Can you give some examples?

Phil

Hi --

Joel VanderWerf wrote:
> George Moschovitis wrote:
>
>> Hello everyone,
>>
>> one of the features of the LISP family of languages that is missing from
>> Ruby are macros. I think they are useful on a lot of occasions so
>> I would like to see Ruby support macros in the future.
>
>
> What you have defined are more like C macros, rather than LISP macros,
> which are hygienic (they operate at the level of syntactic elements,
> rather than characters).

Would Ruby macros, in the Lisp sense, have to manipulate the AST?

And a question (ideally) for Matz, but comments from anyone else are of
course welcome:

Would true macros in Ruby be more prone to abuse than they are in Lisp?

Is there something different about Ruby such that what (supposedly)
works to such acclaim in Lisp would be inappropriate in Ruby?

I'm answering from not very much knowledge of Lisp, and I know the
meta-meta-meta people disagree :slight_smile: but in the form this idea has
always been represented to me -- namely, as a way to introduce
essentially arbitrary syntax -- I've found it unappealing. I think
Ruby can be great for application language things, but the idea of
having {} or . mean new things doesn't do much for me.

I guess I prefer to think of Ruby as a language with a certain syntax
than as a kind of host environment for syntax definition. That's
partly because I like Ruby's syntax, and I think Matz is better at
designing syntax than most of us would be :slight_smile: And also because the
thought of having to learn new syntax for, potentially, every program
is daunting.

David

···

On Tue, 3 Aug 2004, James Britt wrote:

--
David A. Black
dblack@wobblini.net

In article <126117684609.20040802210655@scriptolutions.com>, Lothar

Hello jim,

>> However i think it is quite easy to emulate some form of macro
>> functionality in Ruby. Here is some simple code:

> I've heard Matz say that Ruby will not support macros.

And i hope that he never changes his opinion at this topic.

> They are too easily abused and can mutate the language.

They easily make code much more unreadable.

Banning a feature because it can be misused is a pretty weak rationale.
It might make sense for something like goto where you can provide more
structured alternatives that take care of most cases, but I don't think
macros fall into this case.

It's been said in this thread that Ruby doesn't need macros because it
has blocks but, this too, seems like a very weak argument. After all
Lisp is famous for its support for closures and Lisp programmers still
value the maro support in Lisp.

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. 2) Macros
allow you to evaluate arguments zero or more times whereas functions
and blocks normally eagerly evaluate arguments once. 3) Macros are
inlined so they may execute faster than a block.

Of these benefits, blocks only address point two and that in a rather
clunky fashion.

I think that languages
like D, C# etc now exactly why they don't want something like macros.

How so? I don't know these languages well, but I don't see that they've
done anything to address the problems macros were designed to solve.
They've merely omitted features like meta-programming, dynamic typing,
full multiple inheritance, etc where they thought the cost out-weighed
the benefits.

As said before lisp is different because of the general S-Expression
style of this language.

Different only in that it's easier to implement macros in Lisp. But
more conventional languages, like Dylan, also support macros.

  -- Jesse

···

Scholz <mailinglists@scriptolutions.com> wrote:

Hi,

Would true macros in Ruby be more prone to abuse than they are in Lisp?

  * Lisp does not have syntax. They only have meta syntax
    (i.e. S-expression), Lisp macro do not change its (meta) syntax to
    rely on (I'm ignoring reader macro here). In comparison, Ruby
    does have syntax but no meta syntax, so that you can easily loose
    syntax to rely on by macros in Ruby. You will feel like a stranger
    when you see Ruby programs with a lot of macros. I don't think
    you feel same way when you see Lisp programs with macros.

  * macro system more than simplest one (e.g. C preprocessor macro) is
    VERY difficult to design and implement for languages with usual
    syntax. If you are curious, see Dylan's macro.

  * about 50% of macro usage in Lisp (extending syntax a bit) can
    accomplish using blocks in Ruby. we don't need inlining functions
    when we have other rooms for optimization, for example, C extensions.

  * I admit disclosing abstract syntax tree to Ruby programs can open
    new possibilities. it's good for users at the moment, I guess.
    but it is very bad in a long run unless I design it perfectly.
    I'm sure I will change my mind in AST design and alas, here comes
    another big field of incompatibility.

              matz.

···

In message "Re: Macros in Ruby" on 04/08/03, James Britt <jamesUNDERBARb@neurogami.com> writes:

"George Moschovitis" <gm@navel.gr> schrieb im Newsbeitrag
news:celt6a$1icq$1@ulysses.noc.ntua.gr...

Joel VanderWerf wrote:
> What you have defined are more like C macros, rather than LISP macros,
> which are hygienic (they operate at the level of syntactic elements,
> rather than characters).

You are of course right. But you can do still usefull things. And I
think it can be improved. Any ideas are welcome. Even better would be
support for macros in Ruby 1.9 :slight_smile:

-1

    robert