Macros in Ruby

  • Thread starter George Moschovitis
  • Start date
A

Ara.T.Howard

Remember how the lambda method works: it takes a block parameter and
creates an object out of it. IMO this is very clean; blocks are the
basic building block and procs and bindings are built on top of them.

As to why we cannot remove the call to the lambda method, consider:
1. Ruby does have blocks, and
2. Ruby does not require parens for method calls.

If I write:

(1..10).map { |n| n ** 2 }

Should this be interpreted as:

(1..10).map(lambda { |n| n ** 2 })

or as:

(1..10).map do |n| n ** 2; end

If it were possible to merge blocks and proc objects without
introducting ambiguity and without losing backward compatibility, it
might not be a bad idea. I do not think this is possible, though.

Paul

perhaps a shorthand:

lambda{ puts 'lambda' } => Proc:0xb74041a0
&{ puts 'lambda too' } => Proc:0xb74041a1

i'm probably missing something, but i don't think the syntax '&{' occurs
anywhere now and '&' is already synomynous with blocks/procs/etc.

-a
--
===============================================================================
| EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
| PHONE :: 303.497.6469
| A flower falls, even though we love it;
| and a weed grows, even though we do not love it.
| --Dogen
===============================================================================
 
G

Gavin Sinclair

shouldn't that be '(1..10).map( &lambda { |n| n ** 2 } )'?

No. Jesse expressed a distaste for implicitly passed arguments (i.e.
a block being passed to the method as a hidden, or a special,
parameter. So I presented the above examples as two *different*
possible #map interfaces. In the first one, the block "parameter" is
implicit; in the second one, explicit.
It can! Wether or not a proc object gets created depends on the
called method. [...]

That's context-dependent. My impression is that Jesse thinks that
code snippet in *any* context should evaluate to a lambda.
On the other hand, a Proc created this way is different from one
created using Proc.new or lambda.
The difference which I can think of are:
- Argument passing, a block isn't strict about the arguments
it gets passed, (i.e. it can take any argument). A Proc
object in contrast is strict (like methods). The reason I
can think of is that it is often usefull not to get all arguments
in a block, i.e. 3.times{ puts "Hi, world!" }
- The place where return goes to: in a block 'return' returns
from the method in which it is defined. In a lambda (Proc)
it returns from the lambda expression.

Thanks for pointing these out; they didn't come to mind before.

<snip/>

Gavin
 
G

Gavin Sinclair

perhaps a shorthand:
lambda{ puts 'lambda' } => Proc:0xb74041a0
&{ puts 'lambda too' } => Proc:0xb74041a1
i'm probably missing something, but i don't think the syntax '&{' occurs
anywhere now and '&' is already synomynous with blocks/procs/etc.


If you must have a shortcut, I think 'L' makes more sense.

L { puts 'lambda' } => Proc:0xb74041a0

My aesthetic sense says that a shortcut is unnecessary because
creating explicit lambdas is uncommon (because Ruby has blocks, thank
goodness), and because when you do explicitly create lambdas, they're
usually so cool and saving so much other effort that I don't begrudge
them a few characters :)

Gavin
 
N

Nikolai Weibull

If you must have a shortcut, I think 'L' makes more sense.
L { puts 'lambda' } => Proc:0xb74041a0

Or
\ { puts 'lambda' } => Proc:0xb74041a0

which would make it act sort of like it does in Haskell. However, I
always figured

proc{ puts 'proc or lambda' }

or

lambda{ puts 'proc or lambda' }

was easy enough to understand. Having a special operator for it seems
utterly redundant, as Gavin says, since creating anonymous functions in
this manner is far from as common as in Haskell (and it's not very
common their either). And given that Scheme or Lisp that use them for
basically everything don't have a shorter notation (except for (define)
"rewriting") than (lambda) doesn't seem to warrant a shorter notation
for use in Ruby,
nikolai
 
A

Ara.T.Howard

If you must have a shortcut, I think 'L' makes more sense.

L { puts 'lambda' } => Proc:0xb74041a0


but 'L' is a valid identifier:

~ > cat a.rb
L = 42
L { puts 42 }

~ > ruby a.rb
a.rb:2: undefined method `L' for main:Object (NoMethodError)
from a.rb:2

problematic.
My aesthetic sense says that a shortcut is unnecessary because
creating explicit lambdas is uncommon (because Ruby has blocks, thank
goodness), and because when you do explicitly create lambdas, they're
usually so cool and saving so much other effort that I don't begrudge
them a few characters :)

Gavin

i actually use them quite a bit and would appreciate a shortcut. i sometimes
prefer to have modifiable Proc attributes of object to parameterize their
behaviour rather than messing with inheritence or dynamic redefinition. i also
end up writing methods which take options callbacks for debugging/logging, eg:


def longrunning_database_update arg, opts = {}
pre, pan, post = opts.values_at 'pre', 'pan', 'post'

sql = gen_sql arg

pre.call sql if pre

res =
if pan
t =
Thread.new(Thread.current) do |c|
begin
execute sql
rescue => e
c.raise e
end
end
loop do
break unless t.status
pan.call(get_state)
sleep 0.42
end
t.join
t.value
else
execute sql
end

post.call res if post

res
end


now the call looks somewhat like this



longrunning_database_update 42,
'pre' => lambda{|sql| debug{ "sql <#{ sql }>" }},
'pan' => lambda{|state| debug{ "state <#{ state }>" }},
'post' => lambda{|res| debug{ "res <#{ res }>" }}

i would like say

longrunning_database_update 42,
'pre' => &{|sql| debug{ "sql <#{ sql }>" }},
'pan' => &{|state| debug{ "state <#{ state }>" }},
'post' => &{|res| debug{ "res <#{ res }>" }}


of coures this is totally minor - it would be nice IMHO.

-a
--
===============================================================================
| EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
| PHONE :: 303.497.6469
| A flower falls, even though we love it;
| and a weed grows, even though we do not love it.
| --Dogen
===============================================================================
 
H

Hal Fulton

Ara.T.Howard said:
perhaps a shorthand:

lambda{ puts 'lambda' } => Proc:0xb74041a0
&{ puts 'lambda too' } => Proc:0xb74041a1

i'm probably missing something, but i don't think the syntax '&{' occurs
anywhere now and '&' is already synomynous with blocks/procs/etc.

I've been in favor of this since the last rubyconf when I
discussed it with someone (can't recall who).

I don't think it's ever been an RCR though.


Hal
 
S

Sean O'Dell

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 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
 
M

Michael Neumann

Ara.T.Howard said:
but 'L' is a valid identifier:

~ > cat a.rb
L = 42
L { puts 42 }

~ > ruby a.rb
a.rb:2: undefined method `L' for main:Object (NoMethodError)
from a.rb:2

problematic.

how about "fn" or "fun"? Only one character longer than "&" and IMO
easier to read (especial for ML programmers ;-)

Regards,

Michael
 
M

Mauricio Fernández

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.
 
C

Charles Mills

# if you want to save key strokes you could:
module Kernel
alias l lambda
end
#or
module Kernel
alias fun lambda
end
 
A

Austin Ziegler

i actually use them quite a bit and would appreciate a shortcut. i sometimes
prefer to have modifiable Proc attributes of object to parameterize their
behaviour rather than messing with inheritence or dynamic redefinition. i
also end up writing methods which take options callbacks for
debugging/logging, eg:

I'd do this as:

def long_db_update(arg, callback = nil)
sql = gen_sql(arg)

callback.pre(sql) if callback.respond_to?:)pre)

res =
if callback.respond_to?:)pan)
t = Thread.new(Thread.current) do |c|
begin
execute(sql)
rescue => e
c.raise (e)
end
end

loop do
break unless t.status
callback.pan(get_state)
sleep 0.42
end

t.join
t.value
else
execute(sql)
end

callback.post(res) if callback.respond_to?:)post)
res
end

Then I can create my callback object. With this, I could easily plug
in a debug object (predefined), a GUI object, or anything else, and
my callback becomes part of my defined API. (I would actually even
go as far as modifying callback.post so that its return may
optionally modify res.)

-austin
 
N

Nikolai Weibull

* Michael Neumann said:
how about "fn" or "fun"? Only one character longer than "&" and IMO
easier to read (especial for ML programmers ;-)

And only two or one characters shorter than "proc",
nikolai
 
A

Ara.T.Howard

I'd do this as:

def long_db_update(arg, callback = nil)
sql = gen_sql(arg)

callback.pre(sql) if callback.respond_to?:)pre)

res =
if callback.respond_to?:)pan)
t = Thread.new(Thread.current) do |c|
begin
execute(sql)
rescue => e
c.raise (e)
end
end

loop do
break unless t.status
callback.pan(get_state)
sleep 0.42
end

t.join
t.value
else
execute(sql)
end

callback.post(res) if callback.respond_to?:)post)
res
end

Then I can create my callback object. With this, I could easily plug
in a debug object (predefined), a GUI object, or anything else, and
my callback becomes part of my defined API. (I would actually even
go as far as modifying callback.post so that its return may
optionally modify res.)

-austin

ducktype madness! ;-)

sure, that's alot better than my way - i'm just pointing out that some of us
type 'l-a-m-b-d-a' alot and consider them an undervalued technique for
creating flexible objects since they may easily blur the line between
attributes and behaviour (not that ruby is lacking in flexibility!).

cheers.

-a
--
===============================================================================
| EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
| PHONE :: 303.497.6469
| A flower falls, even though we love it;
| and a weed grows, even though we do not love it.
| --Dogen
===============================================================================
 
D

David A. Black

Hi --

I've been in favor of this since the last rubyconf when I
discussed it with someone (can't recall who).

I don't think it's ever been an RCR though.

Creeping punctuationism.... :)


David
 
H

Hal Fulton

David said:
Creeping punctuationism.... :)

Smile when you say that. Oh, I guess you did.

Actually the & already has that meaning in formal arguments,
so I think of this as just moving toward consistency (much as
* for arrays is usable in or out of a formal arg list).


Hal
 
D

David A. Black

Hi --

Smile when you say that. Oh, I guess you did.

Actually the & already has that meaning in formal arguments,
so I think of this as just moving toward consistency (much as
* for arrays is usable in or out of a formal arg list).

I admit I'd opt for inconsistency over further punctuation in this
case :) But actually I'm not sure I'd agree that & in arglists is the
same usage as & as synonym for lambda. I've always thought of it as a
kind of singular construct, necessary because the whole code-block
thing has that singularity. Also there's this:

pr = lambda {}
some_method &pr

which would become

pr = &{}
some_method &pr

which bugs me in some way involving levels of indirection that I can't
quite put my finger on....


David
 
H

Hal Fulton

David said:
Hi --




I admit I'd opt for inconsistency over further punctuation in this
case :) But actually I'm not sure I'd agree that & in arglists is the
same usage as & as synonym for lambda. I've always thought of it as a
kind of singular construct, necessary because the whole code-block
thing has that singularity. Also there's this:

pr = lambda {}
some_method &pr

which would become

pr = &{}
some_method &pr

which bugs me in some way involving levels of indirection that I can't
quite put my finger on....

I can't put my finger on it either, but I see your point. And that is
perhaps the best argument against it I've seen.


Hal
 
P

Paul Brannan

which bugs me in some way involving levels of indirection that I can't
quite put my finger on....

The way I see it, & and unary * (and possibly in the future unary **)
are related operators in the sense that they transform their argument to
or from a particular representation.

For example, *array transforms array into a list inline, so that an
array can be turned into an argument list for use in passing to a
method. However, *param in a method definition takes a list of
arguments and transforms it into an array. Similarly, it has been
proposed to have **hash turn hash into a list of named arguments, and
**param in a method definition to be used to transform unused named
arguments into a hash. A similar symmetry exists with the & operator;
when called using &proc it turns a proc object into a block and when
used in a method's paramter list it turns a passed block back into a
proc object.

Using &{ ... } as a shorthand for creating proc objects would break this
symmetry. We do currently use * and ** for both the above uses and for
multiplication/exponentiation, but with these operations it is the
binary versions of the operator, not the unary one, so there is no break
in symmetry.

Paul
 
A

Ara.T.Howard

I can't put my finger on it either, but I see your point. And that is
perhaps the best argument against it I've seen.

it's no stranger than this to me

jib:~ > cat a.rb

def method &block; m &block; end
def m &block; block.call; end

method{ puts 42 }

jib:~ > ruby a.rb
42

and feels alot like

const char *cp = "foobar";
printf ("%c\n", *cp);

or

@a = qw(4 2);
$a = \@a;
print @$a,"\n";

(just writing that made me remember why i hate perl!)

but i would agree this is the best argument...

-a
--
===============================================================================
| EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
| PHONE :: 303.497.6469
| A flower falls, even though we love it;
| and a weed grows, even though we do not love it.
| --Dogen
===============================================================================
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,731
Messages
2,569,432
Members
44,832
Latest member
GlennSmall

Latest Threads

Top