Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

yield does not take a block

20 views
Skip to first unread message

Daniel Brockman

unread,
Jun 28, 2005, 4:37:06 AM6/28/05
to
Under ruby 1.9.0 (2005-06-23) [i386-linux], irb 0.9.5(05/04/13),
these forms are not permitted:

yield { .. }
yield &..

But these are okay:

Proc.new.call { .. }
Proc.new.call &..

This is an oversight, right?

--
Daniel Brockman <dan...@brockman.se>

nobuyoshi nakada

unread,
Jun 28, 2005, 6:40:16 AM6/28/05
to
Hi,

At Tue, 28 Jun 2005 17:37:06 +0900,
Daniel Brockman wrote in [ruby-talk:146630]:


> Under ruby 1.9.0 (2005-06-23) [i386-linux], irb 0.9.5(05/04/13),
> these forms are not permitted:
>
> yield { .. }
> yield &..
>
> But these are okay:
>
> Proc.new.call { .. }
> Proc.new.call &..
>
> This is an oversight, right?

Right.


Index: eval.c
===================================================================
RCS file: /cvs/ruby/src/ruby/eval.c,v
retrieving revision 1.791
diff -U2 -p -r1.791 eval.c
--- eval.c 20 Jun 2005 09:59:58 -0000 1.791
+++ eval.c 28 Jun 2005 10:29:44 -0000
@@ -3201,4 +3201,18 @@ rb_eval(self, n)
result = Qundef; /* no arg */
}
+ if (node->nd_body) {
+ PUSH_BLOCK(0, 0);
+ if ((state = EXEC_TAG()) == 0) {
+ struct BLOCK *prev = ruby_block->prev;
+ *ruby_block = *prev;
+ ruby_block->prev = prev;
+ ruby_block->block_obj = rb_eval(self, node->nd_body);
+ SET_CURRENT_SOURCE();
+ result = rb_yield_0(result, 0, 0, YIELD_PROC_CALL, node->nd_state);
+ }
+ POP_BLOCK();
+ if (state) rb_jump_tag(state);
+ break;
+ }
SET_CURRENT_SOURCE();
result = rb_yield_0(result, 0, 0, 0, node->nd_state);
Index: parse.y
===================================================================
RCS file: /cvs/ruby/src/ruby/parse.y,v
retrieving revision 1.387
diff -U2 -p -r1.387 parse.y
--- parse.y 12 Jun 2005 16:56:05 -0000 1.387
+++ parse.y 28 Jun 2005 10:15:29 -0000
@@ -231,5 +231,5 @@ static void void_stmts_gen _((struct par
#define void_stmts(node) void_stmts_gen(parser, node)
static void reduce_nodes _((NODE**));
-static void block_dup_check _((NODE*));
+static NODE *add_iter_block _((NODE*,NODE*));

static NODE *block_append _((NODE*,NODE*));
@@ -1138,7 +1138,5 @@ command : operation command_args
$$ = new_fcall($1, $2);
if ($3) {
- block_dup_check($$);
- $3->nd_iter = $$;
- $$ = $3;
+ $$ = add_iter_block($$, $3);
}
fixpos($$, $2);
@@ -1162,7 +1160,5 @@ command : operation command_args
$$ = new_call($1, $3, $4);
if ($5) {
- block_dup_check($$);
- $5->nd_iter = $$;
- $$ = $5;
+ $$ = add_iter_block($$, $5);
}
fixpos($$, $1);
@@ -1186,7 +1182,5 @@ command : operation command_args
$$ = new_call($1, $3, $4);
if ($5) {
- block_dup_check($$);
- $5->nd_iter = $$;
- $$ = $5;
+ $$ = add_iter_block($$, $5);
}
fixpos($$, $1);
@@ -2561,28 +2555,4 @@ primary : literal
%*/
}
- | kYIELD '(' call_args rparen
- {
- /*%%%*/
- $$ = new_yield($3);
- /*%
- $$ = dispatch1(yield, dispatch1(paren, $3));
- %*/
- }
- | kYIELD '(' rparen
- {
- /*%%%*/
- $$ = NEW_YIELD(0, Qfalse);
- /*%
- $$ = dispatch1(yield, dispatch1(paren, arg_new()));
- %*/
- }
- | kYIELD
- {
- /*%%%*/
- $$ = NEW_YIELD(0, Qfalse);
- /*%
- $$ = dispatch0(yield0);
- %*/
- }
| kDEFINED opt_nl '(' {in_defined = 1;} expr rparen
{
@@ -2610,7 +2580,5 @@ primary : literal
{
/*%%%*/
- block_dup_check($$);
- $2->nd_iter = $1;
- $$ = $2;
+ $$ = add_iter_block($1, $2);
fixpos($$, $1);
/*%
@@ -3215,7 +3183,5 @@ block_call : command do_block
{
/*%%%*/
- block_dup_check($1);
- $2->nd_iter = $1;
- $$ = $2;
+ $$ = add_iter_block($1, $2);
fixpos($$, $1);
/*%
@@ -3296,4 +3262,20 @@ method_call : operation paren_args
%*/
}
+ | kYIELD paren_args
+ {
+ /*%%%*/
+ $$ = new_yield($2);
+ /*%
+ $$ = dispatch1(yield, dispatch1(paren, $2));
+ %*/
+ }
+ | kYIELD
+ {
+ /*%%%*/
+ $$ = NEW_YIELD(0, Qfalse);
+ /*%
+ $$ = dispatch0(yield0);
+ %*/
+ }
| tLPAREN compstmt ')' paren_args
{
@@ -7212,11 +7194,22 @@ aryset_gen(parser, recv, idx)
}

-static void
-block_dup_check(node)
- NODE *node;
+static NODE *
+add_iter_block(node, block)
+ NODE *node, *block;
{
- if (node && nd_type(node) == NODE_BLOCK_PASS) {
- compile_error(PARSER_ARG "both block arg and actual block given");
+ if (node) {
+ switch (nd_type(node)) {
+ case NODE_YIELD:
+ if (!node->nd_body) {
+ nd_set_type(block, NODE_LAMBDA);
+ node->nd_body = block;
+ return node;
+ }
+ case NODE_BLOCK_PASS:
+ compile_error(PARSER_ARG "both block arg and actual block given");
+ }
}
+ block->nd_iter = node;
+ return block;
}

@@ -7794,13 +7787,22 @@ new_yield(node)
{
long state = Qtrue;
+ NODE *body = 0;

if (node) {
- no_blockarg(node);
- if (nd_type(node) == NODE_ARRAY && node->nd_next == 0) {
+ switch (nd_type(node)) {
+ case NODE_BLOCK_PASS:
+ body = node;
+ node = node->nd_iter;
+ nd_set_type(body, NODE_LAMBDA);
+ body->nd_iter = 0;
+ break;
+ case NODE_ARRAY:
+ if (node->nd_next != 0) break;
node = node->nd_head;
state = Qfalse;
- }
- else if (node && nd_type(node) == NODE_SPLAT) {
+ break;
+ case NODE_SPLAT:
state = Qtrue;
+ break;
}
}
@@ -7808,5 +7810,7 @@ new_yield(node)
state = Qfalse;
}
- return NEW_YIELD(node, state);
+ node = NEW_YIELD(node, state);
+ node->nd_body = body;
+ return node;
}

--
Nobu Nakada


Yukihiro Matsumoto

unread,
Jun 28, 2005, 11:32:20 AM6/28/05
to
Hi,

In message "Re: yield does not take a block"


on Tue, 28 Jun 2005 17:37:06 +0900, Daniel Brockman <dan...@brockman.se> writes:

|Under ruby 1.9.0 (2005-06-23) [i386-linux], irb 0.9.5(05/04/13),
|these forms are not permitted:
|
| yield { .. }
| yield &..
|
|But these are okay:
|
| Proc.new.call { .. }
| Proc.new.call &..
|
|This is an oversight, right?

yield is a keyword to pass a value (and control) to the block attached
to the method. I feel strange when I see yield passes a block to an
outer block.

matz.


James Britt

unread,
Jun 28, 2005, 11:49:17 AM6/28/05
to
Yukihiro Matsumoto wrote:
..

> yield is a keyword to pass a value (and control) to the block attached
> to the method. I feel strange when I see yield passes a block to an
> outer block.


Is that good strange or bad strange?

James
--
http://www.ruby-doc.org - The Ruby Documentation Site
http://www.rubyxml.com - News, Articles, and Listings for Ruby & XML
http://www.rubystuff.com - The Ruby Store for Ruby Stuff
http://www.jamesbritt.com - Playing with Better Toys


Yukihiro Matsumoto

unread,
Jun 28, 2005, 12:19:16 PM6/28/05
to
Hi,

In message "Re: yield does not take a block"

on Wed, 29 Jun 2005 00:49:17 +0900, James Britt <jam...@neurogami.com> writes:

|> yield is a keyword to pass a value (and control) to the block attached
|> to the method. I feel strange when I see yield passes a block to an
|> outer block.
|
|Is that good strange or bad strange?

I feel bad strange. Do you?

matz.


James Britt

unread,
Jun 28, 2005, 12:28:46 PM6/28/05
to

No. Good strange.


James


Daniel Brockman

unread,
Jun 28, 2005, 1:30:05 PM6/28/05
to
Yukihiro Matsumoto <ma...@ruby-lang.org> writes:

> yield is a keyword to pass a value (and control) to the block
> attached to the method. I feel strange when I see yield passes a
> block to an outer block.

I feel strange when I see these are not equivalent:

def foo1 &block
block.call &bar
end

def foo2
Proc.new.call &bar
end

def foo3 &block
yield &bar
end

The middle one may be a weird idiom that should be phased out, but I
really think that calling a block captured into a variable should be
equivalent to using yield.

If foo1 and foo3 are not equivalent, then we have an inconsistency.

--
Daniel Brockman <dan...@brockman.se>

Yukihiro Matsumoto

unread,
Jun 28, 2005, 3:45:46 PM6/28/05
to
Hi,

In message "Re: yield does not take a block"

on Wed, 29 Jun 2005 02:30:05 +0900, Daniel Brockman <dan...@brockman.se> writes:

|I feel strange when I see these are not equivalent:
|
| def foo1 &block
| block.call &bar
| end
|
| def foo2
| Proc.new.call &bar
| end
|
| def foo3 &block
| yield &bar
| end

|If foo1 and foo3 are not equivalent, then we have an inconsistency.

Indeed we have inconsistency here if those two are not equivalent, but
I don't think consistency matters most in this case. Using yield
emphasizes passing a value and control to a block given to the method.
On the other hand, "call"ing an block argument (&block) emphasizes
treating a block as a procedural object. If they are focusing
different aspect, they might not be exact same.

It's not a technical issue. Just a matter of how we feel when we see

yield &bar

or

yield {...}

I feel something strange (bad strange) when I see this, just because
it passes a block to another block, which is apparently strange,
whereas

block.call &bar

does not make me feel bad strange, since it is valid syntax in the
microscopic view, even when it is semantically strange.

If you have shown me the reason "yield &bar" is not strange (and is
useful) other than consistency, I'd be glad to apply the Nobu's patch
in [ruby-talk:146636].

matz.


Eric Mahurin

unread,
Jun 28, 2005, 4:17:41 PM6/28/05
to


I tend to agree that the yield should be made consistent with
block.call such that yield would basically be just an alias for
block.call (where block is the block given to the current
method). I think any keyword that can reasonably be made to
look like a method call, should. Makes the syntax more
consistent. If you were starting over, I'd even suggest things
like if/while to be like (or actually) method calls.

but...

Personally, I don't think having yield as a keyword really adds
that much value to the language. The only advantages I see
over explicitly having a &block arg and using block.call are a)
it looks like smalltalk, and b) rdoc parses it better. I think
showing the &block on the def line makes the method interface
clearer up front. I don't use yield at all and haven't missed
it.


__________________________________
Do you Yahoo!?
Yahoo! Mail - Find what you need with new enhanced search.
http://info.mail.yahoo.com/mail_250


Ryan Leavengood

unread,
Jun 28, 2005, 4:49:45 PM6/28/05
to
Eric Mahurin said:
>
> I tend to agree that the yield should be made consistent with
> block.call such that yield would basically be just an alias for
> block.call (where block is the block given to the current
> method). I think any keyword that can reasonably be made to
> look like a method call, should. Makes the syntax more
> consistent. If you were starting over, I'd even suggest things
> like if/while to be like (or actually) method calls.

Though I understand matz's seeing the yielding of a block as a bad kind of
strangeness, I do think consistency is good. If yield and block.call are
different in any way that could be confusing, especially to all these new
Ruby users we've been getting lately. So I agree with Eric here.

I still would like to see a case where a block is yielded, and just how
that would be used. Sounds like potentially confusing code to me.

I also like the idea of if and while being methods, just as long as the
current syntax sugar is maintained.

> Personally, I don't think having yield as a keyword really adds
> that much value to the language. The only advantages I see
> over explicitly having a &block arg and using block.call are a)
> it looks like smalltalk, and b) rdoc parses it better. I think
> showing the &block on the def line makes the method interface
> clearer up front. I don't use yield at all and haven't missed
> it.

I like yield as a keyword, and I think the only reason to use &block is
when you want to save the given block or do some other manipulation on it
(ask for its arity, etc.) It is a lot of extra typing to use an &block
parameter than just calling yield, especially if all you want to do is
yield a value. Conceptually I think the idea of 'yield'ing control to a
block is nice (though I suppose the idea of 'call'ing a block is just as
nice.) But I still don't think yield should be tossed (not that matz ever
would.)

Ryan


Jim Freeze

unread,
Jun 28, 2005, 5:12:15 PM6/28/05
to
* Ryan Leavengood <mrc...@netrox.net> [2005-06-29 05:49:45 +0900]:


> I like yield as a keyword, and I think the only reason to use &block is
> when you want to save the given block or do some other manipulation on it
> (ask for its arity, etc.) It is a lot of extra typing to use an &block
> parameter than just calling yield, especially if all you want to do is
> yield a value. Conceptually I think the idea of 'yield'ing control to a
> block is nice (though I suppose the idea of 'call'ing a block is just as
> nice.) But I still don't think yield should be tossed (not that matz ever
> would.)

The implicit passing of a block (that follows a method call) and
the 'yield' keyword is one of the key signatures of Ruby and one
that gives Ruby a great deal of power with very little typing.

If we had the principle of absolute explicitness for everything,
then it would be more difficult to write DSL's and we wouldn't
have nice apps like rails. In fact, we would probably even have
to add statement ending identifiers, like semicolons....run away run away...

--
Jim Freeze


Eric Mahurin

unread,
Jun 28, 2005, 5:56:39 PM6/28/05
to

I really like the block passing thing in ruby too. I also
think it to be one of the most distinguishing features over
many other languages. What I don't like from the method
definition perspective, is that you have no control over
whether the block is not allowed, optional, or required. I
would have liked being able to define my methods like this to
control it:

def block_prohibited(*args) ... end

def block_allowed(*args,&block=nil)
...
block.call(...) if block
...
end

def block_required(*args,&block)
...
block.call(...)
...
end

Of course these (at least the first and last) break
compatibility, so this ain't gonna happen. But, this would
make sense relative the way other args are defined and assigned
default values.


____________________________________________________
Yahoo! Sports
Rekindle the Rivalries. Sign up for Fantasy Football
http://football.fantasysports.yahoo.com


Jeremy Henty

unread,
Jun 28, 2005, 6:10:20 PM6/28/05
to
In article <2005062821563...@web41129.mail.yahoo.com>, Eric
Mahurin wrote:

> What I don't like ... is that you have no control over whether the


> block is not allowed, optional, or required.

What's wrong with:

def i_hate_blocks
raise "blocks suck" if block_given?
end

Regards,

Jeremy Henty

Bertram Scharpf

unread,
Jun 28, 2005, 6:24:14 PM6/28/05
to
Hi,

Logic demands to allow it. Prohibiting it would mean to
introduce an exception rule (POLS?).

Anyway, the programmer should be saved from fooling himself
inventing more and more complicated constructions.

Bad strange.

Bertram


--
Bertram Scharpf
Stuttgart, Deutschland/Germany
http://www.bertram-scharpf.de


Eric Mahurin

unread,
Jun 28, 2005, 6:28:02 PM6/28/05
to

Of course. I was exaggerating when I said you have "no
control". But, that is kind-of ugly to have to do this for
every method doesn't want a block (most of them). It would be
better if the iterpreter checked this at call time just like it
handles other args (checking the arity). As it is now, you can
pass a block to just about any method that doesn't want a block
and no complaint will be given. If we didn't have
yield/block_given?, this could have been easily handled with
the &block syntax and something like arity.

I'm not suggesting to get rid of yield... I'm just ranting.


__________________________________
Yahoo! Mail
Stay connected, organized, and protected. Take the tour:
http://tour.mail.yahoo.com/mailtour.html

Ryan Leavengood

unread,
Jun 28, 2005, 6:40:10 PM6/28/05
to
Eric Mahurin said:
>
> As it is now, you can
> pass a block to just about any method that doesn't want a block
> and no complaint will be given.

There will also be no bad side affects, besides the code in the block is
never executed. So essentially the person does not understand the
interface to the given method. I don't agree the language should enforce
this, especially given the dynamic nature of Ruby. In fact this reminds me
of all the static-typing sort of arguments we get here now and then.

I equate the above argument to someone saying this should give a warning:

false && a_very_important_method_call()

A language can only go so far in trying to stop bad programmers before it
starts hurting good programmers.

Ryan


James Britt

unread,
Jun 28, 2005, 6:49:16 PM6/28/05
to
Bertram Scharpf wrote:
> Hi,
>
> Am Mittwoch, 29. Jun 2005, 01:19:16 +0900 schrieb Yukihiro Matsumoto:
>
>>In message "Re: yield does not take a block"
>> on Wed, 29 Jun 2005 00:49:17 +0900, James Britt <jam...@neurogami.com> writes:
>>
>>|> yield is a keyword to pass a value (and control) to the block attached
>>|> to the method. I feel strange when I see yield passes a block to an
>>|> outer block.
>>|
>>|Is that good strange or bad strange?
>>
>>I feel bad strange. Do you?
>
>
> Logic demands to allow it. Prohibiting it would mean to
> introduce an exception rule (POLS?).

There's a lot to be said for consistency in a language, to avoid the
complexity introduced by "This is the case, except when it's not."

Ruby has fairly few of these instances, which is part of its appeal for me.

It's nice to be able to layout a small set of ground rules and say that
everything you can derive from them is valid.

>
> Anyway, the programmer should be saved from fooling himself
> inventing more and more complicated constructions.

Saved in what way?

Languages should be designed to enable developers, not protect them from
themselves.

Eric Mahurin

unread,
Jun 28, 2005, 7:23:47 PM6/28/05
to

You could say the same thing about passing too many arguments
to a method. Why does Ruby check this case now? ... because
it is an obvious error that can easily be checked for. The
same could be done automatically for code blocks to methods -
with the right language changes. Having the yield keyword does
make it a little more difficult.

I have no idea what this has to do with static typing. I am a
very strong proponent of duck typing. We are talking about
whether a certain argument (the code block) exists in the call
not what type it is. As it stands now, this code block is
actually statically typed to Proc and not just an object that
responds to call and arity. I would prefer it to be any old
duck that can call and arity.



__________________________________
Discover Yahoo!
Stay in touch with email, IM, photo sharing and more. Check it out!
http://discover.yahoo.com/stayintouch.html


Daniel Brockman

unread,
Jun 28, 2005, 10:21:25 PM6/28/05
to
Yukihiro Matsumoto <ma...@ruby-lang.org> writes:

> If you have shown me the reason "yield &bar" is not strange (and is
> useful) other than consistency, I'd be glad to apply the Nobu's
> patch in [ruby-talk:146636].

I don't have any other reason than consistency. Having used Ruby 1.8
up until yesterday, yield and Proc.new.call are equivalent in my mind.
It seems I will have to drop that identification when moving to 1.9.

The fact that blocks cannot take blocks pre-1.9 has always bugged me,
and I certainly don't think there's anything strange about this code:

define_method :foo do |*args, &block| ... end

However, I agree that most uses of these metablocks (if you will)
probably do not coincide with the use cases of the yield keyword.

So I will not be upset if Nobu's patch is not applied. I will just
make a mental note that Yield Does Not Take a Block and move on.
Should I ever be tempted to pass a block to yield, I will remember
that it doesn't work, and simply call the block explicitly instead.

I guess the reason why yield &block is not strange to me is that the
yield statement yields values, and blocks are just special values.

--
Daniel Brockman <dan...@brockman.se>

Devin Mullins

unread,
Jun 28, 2005, 10:34:13 PM6/28/05
to
Eric Mahurin wrote:

>Having the yield keyword does
>make it a little more difficult.
>
>

Actually, it makes it a lot more difficult. Consider:

irb(main):039:0> def blah
irb(main):040:1> eval "yield", binding
irb(main):041:1> end
=> nil
irb(main):042:0> blah { puts 5 }
5
=> nil

In any case, I don't have a strong opinion on the "arity" of blocks. I
*do* have a fairly strong opinion that consistency should be favored
wherever possible, but nothing real to back it up, other than that (the
lack of) it is what I dislike most about Java (primitives, null,
Serializable, java.lang...), and it is what I like most about Ruby.

>As it stands now, this code block is
>actually statically typed to Proc and not just an object that
>responds to call and arity. I would prefer it to be any old
>duck that can call and arity.
>
>

Agreed. That code be done without changing any of the current syntax, too.

irb(main):047:0> blah(&proc{puts 5})
5
=> nil

irb(main):048:0> p = Object.new
=> #<Object:0x2b31990>
irb(main):049:0> class << p
irb(main):050:1> def call
irb(main):051:2> puts 5
irb(main):052:2> end
irb(main):053:1> end
=> nil
irb(main):054:0> blah(&p)
TypeError: wrong argument type Object (expected Proc)
from (irb):54
from :0

Boo. :(

Devin
But yay, Ruby, in general.

Also, yay for just having an irb session sitting around in my taskbar.
Does that make me a packrat?

Robert Klemme

unread,
Jun 29, 2005, 6:03:58 AM6/29/05
to

Note though that yield and &c.call work quite differently. This has for
example performance implications.

Kind regards

robert

Eric Mahurin

unread,
Jun 29, 2005, 8:37:16 AM6/29/05
to
--- Robert Klemme <bob....@gmx.net> wrote:
> Note though that yield and &c.call work quite differently.
> This has for example performance implications.

I didn't know about this advantage. From my quick benchmarks,
I found yield to take half the time as Proc#call in a loop with
the block being empty. I'd imagine the performance difference
is because yield is working with a statically typed Proc,
whereas call is using a normal dynamically typed object to
#call. I'd imagine as ruby matures, the performance difference
between these two would become negligible or zero. I'd hope at
some point ruby would make optimizations when it knows the
exact class of an object - do method lookup at compile time.


__________________________________
Yahoo! Mail Mobile
Take Yahoo! Mail with you! Check email on your mobile phone.
http://mobile.yahoo.com/learn/mail


Robert Klemme

unread,
Jun 29, 2005, 8:46:37 AM6/29/05
to
Eric Mahurin wrote:
> --- Robert Klemme <bob....@gmx.net> wrote:
>> Note though that yield and &c.call work quite differently.
>> This has for example performance implications.
>
> I didn't know about this advantage. From my quick benchmarks,
> I found yield to take half the time as Proc#call in a loop with
> the block being empty. I'd imagine the performance difference
> is because yield is working with a statically typed Proc,
> whereas call is using a normal dynamically typed object to
> #call.

Yes. More preceisely the overhead of &b.call is in the creation of the
proc (i.e. transforming the block, storing the closure and registering the
result with GC) - with 'yield' there is no object around.

> I'd imagine as ruby matures, the performance difference
> between these two would become negligible or zero.

Probably but IMHO not very likely. Maybe the gap closes but my guess
would be that it remains significant.

> I'd hope at
> some point ruby would make optimizations when it knows the
> exact class of an object - do method lookup at compile time.

IMHO this is close to impossible as knowing the class of an object tells
you nothing definite about which methods it supports and what signature
they have. (see all the discussions about static typing)

Kind regards

robert

Eric Mahurin

unread,
Jun 29, 2005, 9:58:53 AM6/29/05
to

Probably correct. I think there may be a little too much
flexibility in the ruby language that will prevent future
optimizations. I think the destructive modification of a class
and of an object's class (making its class a singleton) are the
main culprits. If these were non-destructive (returning a new
class or new object with a singleton class), it would have
allowed more optimization. To me, discussions about
destructive vs. non-destructive methods (reverse! vs. reverse)
are nothing compared to these.

Adam P. Jenkins

unread,
Jun 29, 2005, 11:58:34 AM6/29/05
to
Eric Mahurin wrote:
> Personally, I don't think having yield as a keyword really adds
> that much value to the language. The only advantages I see
> over explicitly having a &block arg and using block.call are a)
> it looks like smalltalk, and b) rdoc parses it better. I think
> showing the &block on the def line makes the method interface
> clearer up front. I don't use yield at all and haven't missed
> it.

I completely agree with this. I think closures are one of the most
useful features of Ruby, but I still don't understand what the point of
having blocks and yield is. In all other languages I've used that have
closures, such as Scheme, ML, Haskell, OCaml, and even Javascript, a
closure is just an object like any other object, that happens to have a
special literal syntax for creating them. If you want to pass a closure
to another function, you just pass it like any other argument.

The way ruby does it with blocks/yield has several disadvantages:

1) There's an arbitrary limit of 1 on the number of blocks you can pass
to a function. If you want to pass more than 1, you need to convert all
but the last block to a proc.

2) The block argument can be implicit, so you can't see from the
function signature that there is a block argument.

3) You get a problem akin to Java's primitive/Object separation, where
in some contexts you need a block, and have to convert another callable
object to a block, and in other contexts you need a proc, and have to
convert a block to a proc.

Let me expand on the last item. In functional languages like Scheme,
ML, or Haskell, all functions are closures, whether they're named or
anonymous, and can be used interchangeably. So, say I wanted to apply a
function to each element of a list, I'd write something like this in ML:

for_each myArray print

for_each takes a list as its first argument, and a function with 1
parameter as its second argument, and applies the function to each
element of the list. In Ruby, since there's a distinction between
blocks, closures, and functions, I can't just pass print, even though
it's a function of 1 parameter. Rather I have to wrap print in a block:

myArray.each { |elem| print elem }

Wouldn't it have been cool to just be able to write:

myArray.each print

Overall, it's not a big problem, but I do think the fact that there's a
distinction between blocks, procs, and functions is one of the main
warts in the Ruby language.

Adam

Daniel Brockman

unread,
Jun 29, 2005, 12:16:57 PM6/29/05
to
Eric Mahurin <eric_m...@yahoo.com> writes:

> I think the destructive modification of a class and of an object's
> class (making its class a singleton) are the main culprits.

However, I ``destructively'' modify standard library classes and
modules all the time. This is a major selling point for Ruby.

> If these were non-destructive (returning a new class or new object
> with a singleton class), it would have allowed more optimization.

I don't see how returning a new class could be useful in any way.
For example, what should happen if you say this?

class Numeric ; def infinite? ; false end end

--
Daniel Brockman <dan...@brockman.se>

Kent Sibilev

unread,
Jun 29, 2005, 12:29:34 PM6/29/05
to
Yes, but consider this:

irb(main):001:0> def display x
irb(main):002:1> puts x
irb(main):003:1> end
=> nil
irb(main):004:0> (1..5).each &method(:display)
1
2
3
4
5
=> 1..5
irb(main):005:0>

Kent.

Eric Mahurin

unread,
Jun 29, 2005, 12:48:15 PM6/29/05
to
--- "Adam P. Jenkins" <tho...@theshire.com> wrote:
> Rather I have to wrap print
> in a block:
>
> myArray.each { |elem| print elem }
>
> Wouldn't it have been cool to just be able to write:
>
> myArray.each print

The reason you can't is because a method name by itself calls
the method instead of returning the method object. If you had
to put () to make the call and the method name by itself
returned the method object (I would have preferred that), you
could do this:

myArray.each(&print)

but, this should work fine right now:

myArray.each(&method(:print))


__________________________________
Discover Yahoo!
Have fun online with music videos, cool games, IM and more. Check it out!
http://discover.yahoo.com/online.html


Eric Mahurin

unread,
Jun 29, 2005, 12:59:27 PM6/29/05
to
--- Daniel Brockman <dan...@brockman.se> wrote:
> Eric Mahurin <eric_m...@yahoo.com> writes:
>
> > I think the destructive modification of a class and of an
> object's
> > class (making its class a singleton) are the main culprits.
>
> However, I ``destructively'' modify standard library classes
> and
> modules all the time. This is a major selling point for
> Ruby.

I'm not going to argue that it is not useful, because it is and
I use it. I'm just saying that being able to modify a class
and the (singleton) class of an object at runtime will prohibit
some amount of optimization within ruby. If these were done at
compile/parse time or nondestructively (returning a new
class/object), it would be easier to optimize ruby, but
obviously less flexible.

Adam P. Jenkins

unread,
Jun 29, 2005, 1:19:21 PM6/29/05
to
Eric Mahurin wrote:
> --- "Adam P. Jenkins" <tho...@theshire.com> wrote:
>
>>Rather I have to wrap print
>>in a block:
>>
>> myArray.each { |elem| print elem }
>>
>>Wouldn't it have been cool to just be able to write:
>>
>> myArray.each print
>
>
> The reason you can't is because a method name by itself calls
> the method instead of returning the method object.

Ok, fair enough. I would still prefer just

myArray.each :print

or
myArray.each &print

than having to wrap it in a block.

If you had
> to put () to make the call and the method name by itself
> returned the method object (I would have preferred that), you
> could do this:
>
> myArray.each(&print)
>
> but, this should work fine right now:
>
> myArray.each(&method(:print))

Cool, I didn't know about that. Still,

myArray.each &method(:print)
myArray.each {|e| print e }

Not much advantage really.

Obviously you can do what you need to do in the current Ruby
implementation, it's just annoying and inconsistent in the same way that
it's annoying in Java that you need to box or unbox primitive types
depending on the context. Even the Java 1.5 syntactic sugar for
autoboxing doesn't completely hide the distinction. Coming from
programming in functional languages, Ruby's distinction between blocks,
closures, and methods seems similarly unnecessary at a language level,
though like Java's primitive/Object distinction, it's probably a useful
compromise for runtime efficiency.

Adam

Daniel Brockman

unread,
Jun 29, 2005, 1:20:23 PM6/29/05
to
"Adam P. Jenkins" <tho...@theshire.com> writes:

> In all other languages I've used that have closures, such as Scheme,
> ML, Haskell, OCaml, and even Javascript, a closure is just an object
> like any other object, that happens to have a special literal syntax
> for creating them.

[...]

> The way ruby does it with blocks/yield has several disadvantages:
>
> 1) There's an arbitrary limit of 1 on the number of blocks you can
> pass to a function. If you want to pass more than 1, you need to
> convert all but the last block to a proc.

The languages you mentioned above all have this ``arbitrary limit.''
Consider O'Caml. You can only give one block to the `fun' keyword.
Or JavaScript. Certainly, the `function' keyword only takes one
argument list and one code block.

In fact, these languages have the additional ``arbitrary limit'' that
code blocks cannot be passed to user-defined methods.

What I mean is that Ruby allows this,

lambda { |a, b, c| ... }

as well as this

moomin { |a, b, c| ... }

and this ---

snufkin foo, bar do |a, b, c| ... end

Heck, Ruby 1.9 even allows this shorthand for lambdas,

{ |a, b, c| ... }

but that's beside the point. The point is that JavaScript only
allows this:

function (a, b, c) { ... }

That is to say, you cannot define `moomin' in a way that makes this
valid JavaScript code:

moomin (a, b, c) { ... }

The same goes for all the other languages. (Well, except for Scheme,
which really actually lets you define arbitrary syntactic forms, but
we all know that Lisp is inherently superior to everything else, so I
will just pretend you didn't mention it.)

Clearly, when it comes to blocks, Ruby's syntax is far more general
than that of other mortal (i.e., non-Lisp) languages.

While a JavaScript programmer would go like this,

array.sort(function (a, b) { ... })

a Ruby programmer could go like this ---

array.sort &lambda { |a, b| ... }

that would be the literal translation. But Ruby takes another step;
it lets you give code blocks directly to _any_ method,

array.sort { |a, b| ... }

not just `lambda'. This is _better_ than most languages can do.

--
Daniel Brockman <dan...@brockman.se>

Adam P. Jenkins

unread,
Jun 29, 2005, 3:45:35 PM6/29/05
to
Daniel Brockman wrote:
> "Adam P. Jenkins" <tho...@theshire.com> writes:
>
>
>>Eric Mahurin wrote:
>>
>>
>>>"Adam P. Jenkins" <tho...@theshire.com> wrote:
>>>
>>>
>>>>Rather I have to wrap print in a block:
>>>>
>>>> myArray.each { |elem| print elem }
>>>>
>>>>Wouldn't it have been cool to just be able to write:
>>>>
>>>> myArray.each print
>
>
> Due to the deeply object-oriented nature of Ruby, I think your
> semantics (call a global method with each element as argument) are
> neither very feasible nor very useful.

Not true at all. An OO language just has to support the concept of a
bound method reference. For example, in Python:

# Here's an unbound method of the "file" class:
>>> file.write
<method 'write' of 'file' objects>
>>>

# Here's a bound method
>>> sys.stdout.write
<built-in method write of file object at 0xb7fb9060>

# Here's how you can use a bound method reference
>>> w=sys.stdout.write
>>> w("Hello\n")
Hello
>>>

The assignment to "w" creates a bound method reference, that not only
knows what method it refers to, but which object to send the method call
to. C# implements a similar concept, and there's no fundamental reason
that any OO language couldn't. So I don't agree at all that OO and
functional paradigms don't mix in this regard.

>
>
>>>The reason you can't is because a method name by itself calls
>>>the method instead of returning the method object.
>>
>>Ok, fair enough. I would still prefer just
>>
>> myArray.each :print
>
>

> Unfortunately, there is no straightforward way to redefine `each',
> since every class has its own implementation.

I'm just having an theoretical "could have been" discussion. I'm not
suggesting there's any practical way to change things at this point.

>>Obviously you can do what you need to do in the current Ruby
>>implementation, it's just annoying and inconsistent in the same way
>>that it's annoying in Java that you need to box or unbox primitive
>>types depending on the context. Even the Java 1.5 syntactic sugar
>>for autoboxing doesn't completely hide the distinction. Coming from
>>programming in functional languages, Ruby's distinction between
>>blocks, closures, and methods seems similarly unnecessary at a
>>language level, though like Java's primitive/Object distinction,
>>it's probably a useful compromise for runtime efficiency.
>
>

> It doesn't sound like you have anything concrete to contribute.
> No, Ruby is not Haskell --- so what?

Hey now, that's an unnecessary low blow. Or are you suggesting we
should forgo theoretical discussion, and limit ourselves to discussing
things which are actually likely to make it into the next version of Ruby?

This is a language newsgroup, and this a thread about arguably
inconsistent semantics concerning blocks and procs. I'm not suggesting
Ruby should be a certain way *because* some other language is that way,
but rather I'm critiquing a certain aspect of the Ruby language by way
of comparison to other languages.

When I first started programming in Ruby, I didn't understand why it had
separate concepts for blocks and closures, but I figured maybe it would
become apparent after using it for a while. One guess I made was that
maybe the first version of Ruby only had block/yield, and when it became
apparent that blocks were too limited, procs were added as a more
general mechanism, but block/yield had to stay for backward
compatibility. After using Ruby at work for several months now, I've
come to the conclusion that there is no good reason for the distinction
at the language level, though at an implementation level, I have seen it
mentioned that yield operates faster than Proc#call. I'd still be
interested though in hearing if there is another rationale for the
distinction.

Adam

twi...@comcast.net

unread,
Jun 29, 2005, 3:57:59 PM6/29/05
to
> The languages you mentioned above all have this ``arbitrary limit.''
> Consider O'Caml. You can only give one block to the `fun' keyword.
> Or JavaScript. Certainly, the `function' keyword only takes one
> argument list and one code block.
>
> In fact, these languages have the additional ``arbitrary limit'' that
> code blocks cannot be passed to user-defined methods.

Your example is deceptive. In Ruby, def, if, begin, and while all have the same sort of syntax - but do not take a block. They take some lines of code which then have their own independent lexical scope. Just like in those other language, 'fun' is different from everything else.

Ruby, like those other languages, supports the passing of lambda functions, though with not nearly the flexibility that, say, OCaml allows. Ruby also supports blocks, whose syntax is nice, but whose semantic distinction from lambdas is unclear to me.

> a Ruby programmer could go like this ---
>
> array.sort &lambda { |a, b| ... }
>
> that would be the literal translation. But Ruby takes another step;
> it lets you give code blocks directly to _any_ method,
>
> array.sort { |a, b| ... }
>
> not just `lambda'.

Granted.

> This is _better_ than most languages can do.

Why? (And don't say 'syntax', because that can be sweetened -- as you say, 1.9 does just that.)

Devin
Inquisitive, not argumentative...

mathew

unread,
Jun 29, 2005, 4:12:00 PM6/29/05
to
Eric Mahurin wrote:
> You could say the same thing about passing too many arguments
> to a method. Why does Ruby check this case now?

I think a another similar question is why ruby doesn't allow you to
declare the variables you're actually planning to use in a given
context, allowing the system to give a helpful error if you accidentally
mistype one of them, instead of leaving you to track down why variables
don't have the value you expect.

Actually, it's not really a question, as I know the answer: the language
developers have a religious objection to declarations, and think nobody
should be allowed to use them, even if they want to. (See
<URL:http://rcrchive.net/rejected.html#rcr8>)

Why is it good to have to declare the arguments you expect, but bad to
have to declare the variables or code blocks you expect? I don't know...

> I have no idea what this has to do with static typing.

Probably nothing, though you could wax philosophical over whether a
block of code is a 'type' or not. Variable declaration has nothing to
do with static typing either; however, some people seem to see
everything as a clandestine attempt to introduce static typing... It's
some kind of Post Java Trauma Disorder I think.


mathew

Adam P. Jenkins

unread,
Jun 29, 2005, 4:49:06 PM6/29/05
to
Daniel Brockman wrote:
> "Adam P. Jenkins" <tho...@theshire.com> writes:
>
>
>>In all other languages I've used that have closures, such as Scheme,
>>ML, Haskell, OCaml, and even Javascript, a closure is just an object
>>like any other object, that happens to have a special literal syntax
>>for creating them.
>
>
> [...]
>
>
>>The way ruby does it with blocks/yield has several disadvantages:
>>
>>1) There's an arbitrary limit of 1 on the number of blocks you can
>> pass to a function. If you want to pass more than 1, you need to
>> convert all but the last block to a proc.
>
>
> The languages you mentioned above all have this ``arbitrary limit.''
> Consider O'Caml. You can only give one block to the `fun' keyword.
> Or JavaScript. Certainly, the `function' keyword only takes one
> argument list and one code block.

The "function" keyword is not a function, it's a keyword for defining a
function, equivalent to "def" in Ruby, or "fun" in O'Caml. I'm talking
about the passing multiple closures to a function. In Ruby you need to
use a different syntax to pass more than one closure argument than if
you only want to pass one. That's what I was talking about.

obj.method_that_takes_one_block {|a,b| .... }

obj.method_that_takes_two_blocks(proc{|a| ... }) {|b| ... }

What would seem cleaner to me would be if the {|params| code } syntax
evaluated to a proc. Then you'd just say:

obj.method_that_takes_two_blocks {|a| ... }, {|b| ...}, third_arg

See, in the last (hypothetical) syntax, proc is just a kind of object
that happens to have a literal syntax for defining it, just as arrays
and hashes do, but is otherwise just like any other object, and is
passed as an argument just as anything else is passed as an argument.
That's all I'm suggesting, and wondering why it's not that way, or if it
couldn't be made that way in Ruby 1.9.

>
> In fact, these languages have the additional ``arbitrary limit'' that
> code blocks cannot be passed to user-defined methods.
>
> What I mean is that Ruby allows this,
>
> lambda { |a, b, c| ... }
>
> as well as this
>
> moomin { |a, b, c| ... }
>
> and this ---
>
> snufkin foo, bar do |a, b, c| ... end
>
> Heck, Ruby 1.9 even allows this shorthand for lambdas,
>
> { |a, b, c| ... }
>
> but that's beside the point. The point is that JavaScript only
> allows this:
>
> function (a, b, c) { ... }
>
> That is to say, you cannot define `moomin' in a way that makes this
> valid JavaScript code:
>
> moomin (a, b, c) { ... }


This is just a semantic game having to do with the overloading of the
word "block" in different language definitions. In the Ruby definition
the word "block" is used to mean a type of anonymous closure, whereas in
most other languages the word "block" is usually used to refer to an
enclosed section of code, such as what would be executed inside an if or
else branch. You can do all the Ruby things you're showing above with
Javascript, it's just that the syntax is different, and what Ruby calls
a "block", Javascript calls a "closure", or "function object".

The Javascript equivalent of what Ruby calls a "block" would be this:

Ruby:
{|a, b| somecode }

Javascript:
function(a, b) { somecode }

Except that Javascript doesn't have two different types of closures, so
the Javascript closure is really closer to a "proc" in Ruby, since it
evaluates to a Function object, which can be directly assigned to a
variable, or passed as a parameter to a function.

>
> The same goes for all the other languages. (Well, except for Scheme,
> which really actually lets you define arbitrary syntactic forms, but
> we all know that Lisp is inherently superior to everything else, so I
> will just pretend you didn't mention it.)
>
> Clearly, when it comes to blocks, Ruby's syntax is far more general
> than that of other mortal (i.e., non-Lisp) languages.
>
> While a JavaScript programmer would go like this,
>
> array.sort(function (a, b) { ... })
>
> a Ruby programmer could go like this ---
>
> array.sort &lambda { |a, b| ... }
>
> that would be the literal translation. But Ruby takes another step;
> it lets you give code blocks directly to _any_ method,
>
> array.sort { |a, b| ... }
>
> not just `lambda'. This is _better_ than most languages can do.

Semantically,

array.sort {|a,b| .. }

is the same as Javascript's

array.sort(function(a,b) { ... })

so you're still just playing semantic games with Ruby's unusual use of
the word "block" to claim some fundamental advantage for Ruby.
Basically the difference just comes down to the fact that you don't have
to use the "function" keyword in Ruby. The real difference, and the one
that I'm questioning the usefulness of, is the fact that Ruby provides
several different ways to do the same thing:

def func1
yield
end

def func2(&block)
block.call
end

def func3(block)
block.call
end

blockvar = lambda { ... }

func1 { ... }
func1 &blockvar

func2 { ... }
func2 &blockvar

func3(lambda { ... })
func3 blockvar

I wouldn't see anything wrong with having all these different ways of
passing closures if I could see some different functionality being
offered by the different methods. As it is, I'm a little baffled as to
why they all couldn't be unified down to

def func(block)
block.call
end

func { ... }

And for a function that takes two blocks:

def func(block1, block2)
block1.call
block2.call
end

func { ... }, { ... }

Etc. Is it really just a matter of backward compatibility at this
point? (By "just", I don't mean to suggest this is an insignificant
concern.) Is it that people like not having to type in the extra
parameter when they're defining a function? Is it that "yield"
inherently allows for faster execution in the common 1 block case? Is
there some other advantage to "yield" that I'm missing?

Adam

Daniel Brockman

unread,
Jun 29, 2005, 7:20:27 PM6/29/05
to
"Adam P. Jenkins" <tho...@theshire.com> writes:

> Daniel Brockman wrote:
>
>> Due to the deeply object-oriented nature of Ruby, I think your
>> semantics (call a global method with each element as argument) are
>> neither very feasible nor very useful.
>
> Not true at all. An OO language just has to support the concept of
> a bound method reference. For example, in Python:
>
> # Here's an unbound method of the "file" class:
> >>> file.write
> <method 'write' of 'file' objects>
> >>>

In Ruby,

IO.instance_method :write #=> #<UnboundMethod: IO#write>

> # Here's a bound method
> >>> sys.stdout.write
> <built-in method write of file object at 0xb7fb9060>

In Ruby,

$stdout.method :write

> # Here's how you can use a bound method reference
> >>> w=sys.stdout.write
> >>> w("Hello\n")
> Hello
> >>>

In Ruby,

w = $stdout.method :write
w["Hello\n"] # or w.call "Hello\n"

> The assignment to "w" creates a bound method reference, that not
> only knows what method it refers to, but which object to send the
> method call to. C# implements a similar concept, and there's no
> fundamental reason that any OO language couldn't.

Indeed, and Ruby does precisely this.

> So I don't agree at all that OO and functional paradigms don't mix
> in this regard.

I think you missed the point. You originally suggested we have this

foo.each print

be equivalent to this:

foo.each { |x| print x }

Note how print is a ``global function,'' rather than a method on x.
This is what I objected to, my point being that --- Ruby being a
deeply object-oriented language --- it would be more natural for

foo.each print

to mean

foo.each { |x| print.bind(x).call }

Of course, as I said, a more useful form would be

foo.each :print

for

foo.each { |x| x.__send__ :print }

(I believe it's more common to invoke a method on each element of a
collection than it is to give each element to a unary function.)

>>>> The reason you can't is because a method name by itself calls
>>>> the method instead of returning the method object.
>>>
>>> Ok, fair enough. I would still prefer just
>>>
>>> myArray.each :print
>>
>> Unfortunately, there is no straightforward way to redefine `each',
>> since every class has its own implementation.
>
> I'm just having an theoretical "could have been" discussion. I'm not
> suggesting there's any practical way to change things at this point.

I'm also having a mostly theoretical discussion. The above statement
was not meant to criticize you. I said, ``unfortunately, you can't
redefine `each', but look, you can define your own method in the
following useful way.'' (But you cut that part out when quoting me.)

>>> Obviously you can do what you need to do in the current Ruby
>>> implementation, it's just annoying and inconsistent in the same
>>> way that it's annoying in Java that you need to box or unbox
>>> primitive types depending on the context. Even the Java 1.5
>>> syntactic sugar for autoboxing doesn't completely hide the
>>> distinction. Coming from programming in functional languages,
>>> Ruby's distinction between blocks, closures, and methods seems
>>> similarly unnecessary at a language level, though like Java's
>>> primitive/Object distinction, it's probably a useful compromise
>>> for runtime efficiency.
>>
>> It doesn't sound like you have anything concrete to contribute.
>> No, Ruby is not Haskell --- so what?
>
> Hey now, that's an unnecessary low blow.

I apologize. I thought the above paraghaph looked like a pointless
rant about how ``it would be better if it didn't suck.'' But I think
I see where you are going with the analogy now: blocks are primitives
and procs are Objects, and we should get rid of the primitives and
stick to Objects unless it hurts performance?

Simply put, you think that the yield keyword should be abolished along
with the concept of ``block parameters'' --- right? So

foo { ... }

would be a method call with one regular parameter, and

foo { ... }, { ... }

would simply be a method call with two regular parameters. I don't
think this is an insane proposal. But what about this syntax?

foo { ... }.bar { ... }

I don't think these alternatives are very attractive:

(foo { ... }).bar { ... }

foo({ ... }).bar { ... }

Honest question: What are some use cases for multiple blocks?
(Please don't tell me you want `if' to be a method.)

[...]

> When I first started programming in Ruby, I didn't understand why it
> had separate concepts for blocks and closures,

Please use one of the terms `lambda', `proc', or possibly `function'
unless there is a specific reason to limit discussion to closures.

def moomin
foo = lambda { |x| x * 2 + 1 }
lambda { |x| 7 / foo.call x }
end

bar = moomin

Here, `foo' and `bar' are both lambdas, but only `bar' is a closure.

> but I figured maybe it would become apparent after using it for a
> while. One guess I made was that maybe the first version of Ruby
> only had block/yield, and when it became apparent that blocks were
> too limited, procs were added as a more general mechanism, but
> block/yield had to stay for backward compatibility. After using
> Ruby at work for several months now, I've come to the conclusion
> that there is no good reason for the distinction at the language
> level, though at an implementation level, I have seen it mentioned
> that yield operates faster than Proc#call. I'd still be interested
> though in hearing if there is another rationale for the distinction.

Actually, the more I think about it, the more reasonable it seems.
People, help: Why do we need blocks to be so damn special?

--
Daniel Brockman <dan...@brockman.se>

Daniel Brockman

unread,
Jun 29, 2005, 2:10:16 PM6/29/05
to
"Adam P. Jenkins" <tho...@theshire.com> writes:

> Eric Mahurin wrote:
>
>> "Adam P. Jenkins" <tho...@theshire.com> wrote:
>>
>>> Rather I have to wrap print in a block:
>>>
>>> myArray.each { |elem| print elem }
>>>
>>> Wouldn't it have been cool to just be able to write:
>>>
>>> myArray.each print

Due to the deeply object-oriented nature of Ruby, I think your


semantics (call a global method with each element as argument) are
neither very feasible nor very useful.

>> The reason you can't is because a method name by itself calls


>> the method instead of returning the method object.
>
> Ok, fair enough. I would still prefer just
>
> myArray.each :print

Unfortunately, there is no straightforward way to redefine `each',
since every class has its own implementation. But you can define
another method for sending a message to each element in a collection.

module Enumerable
def each! message, *args, &block
each { |x| x.__send__ message, *args, &block }
end
end

I'm sorry I couldn't think of a better name than `each!'.

>> If you had to put () to make the call and the method name by itself
>> returned the method object (I would have preferred that), you could
>> do this:

[...]

I just want to say that I'm really glad to be able to leave out the
parentheses. I prefer

array.compact!

over

array.compact!()

any day.

> Cool, I didn't know about that. Still,
>
> myArray.each &method(:print)
> myArray.each {|e| print e }
>
> Not much advantage really.

I have been toying with the idea of binding parameters automatically.
The general case would be to bind all parameters to, e.g., @1, @2, @3,
and so on. But the most useful case is the first parameter. What if
a single lone snail referred to the first parameter?

Then you could write the above as

myArray.each { print @ }

I know from experience that this can make people cry out ``hideous!''
and ``get away from our language, you subversive Perl advocate.''
It can also make people say ``hey, that makes a lot of sense.''

(For the record, I don't advocate Perl, per se, but I do recognize
that it was designed by a real linguist with good ideas.)

I don't think automatical currying or automatic method boxing or
anything like that makes sense in Ruby. But I do think this

ipv4s.collect! { IPv4Address[@] }
publics = ipv4s.select { @.public? }
privates = ipv4s.select { @.private? }
loopbacks = ipv4s.select { @.loopback? }

looks better than this

ipv4s.collect! { |x| IPv4Address[x] }
publics = ipv4s.select { |x| x.public? }
privates = ipv4s.select { |x| x.private? }
loopbacks = ipv4s.select { |x| x.loopback? }

looks better than this

ipv4s.collect! { |ip| IPv4Address[ip] }
publics = ipv4s.select { |ip| ip.public? }
privates = ipv4s.select { |ip| ip.private? }
loopbacks = ipv4s.select { |ip| ip.loopback? }

Those repetitive microscopically-scoped parameter names don't add any
explanatory value or increased readability --- they're just clutter.

> Obviously you can do what you need to do in the current Ruby
> implementation, it's just annoying and inconsistent in the same way
> that it's annoying in Java that you need to box or unbox primitive
> types depending on the context. Even the Java 1.5 syntactic sugar
> for autoboxing doesn't completely hide the distinction. Coming from
> programming in functional languages, Ruby's distinction between
> blocks, closures, and methods seems similarly unnecessary at a
> language level, though like Java's primitive/Object distinction,
> it's probably a useful compromise for runtime efficiency.

It doesn't sound like you have anything concrete to contribute.


No, Ruby is not Haskell --- so what?

--
Daniel Brockman <dan...@brockman.se>

Daniel Brockman

unread,
Jun 29, 2005, 1:28:19 PM6/29/05
to
Eric Mahurin <eric_m...@yahoo.com> writes:

> If these [modifying a class/singleton class] were done at


> compile/parse time or nondestructively (returning a new
> class/object), it would be easier to optimize ruby, but obviously
> less flexible.

You didn't respond to my question:

Eric Mahurin

unread,
Jun 29, 2005, 2:14:22 PM6/29/05
to
--- Daniel Brockman <dan...@brockman.se> wrote:
> You didn't respond to my question:
>
> >> I don't see how returning a new class could be useful in
> any way.
> >> For example, what should happen if you say this?
> >>
> >> class Numeric ; def infinite? ; false end end

The non-destructive version of this would be (simple
inheritance):

class MyNumeric < Numeric; def infinite?;false;end;end

I know that is not what you wanted and not nearly as useful. I
was just making the point that this useful behavior (modifying
classes at run-time) does come at a cost: it ties ruby to a
very dynamic object model that makes it difficult for ruby to
do certain types of optimizations.

Florian Frank

unread,
Jun 30, 2005, 12:31:23 AM6/30/05
to
Adam P. Jenkins wrote:

> obj.method_that_takes_two_blocks {|a| ... }, {|b| ...}, third_arg
>
> See, in the last (hypothetical) syntax, proc is just a kind of object
> that happens to have a literal syntax for defining it, just as arrays
> and hashes do, but is otherwise just like any other object, and is
> passed as an argument just as anything else is passed as an argument.
> That's all I'm suggesting, and wondering why it's not that way, or if
> it couldn't be made that way in Ruby 1.9.

It is made that way in current Ruby 1.9:

>> def compose(f, g) { |x| f[g[x]] } end
=> nil
>> h = compose({ |x| 2 * x }, { |x| x + 1 })
=> #<Proc:0x00540dbc@(irb):8>
>> h[3]
=> 8

--
Florian Frank

Daniel Amelang

unread,
Jun 30, 2005, 12:50:42 AM6/30/05
to
Well, let's look at what our code looks like now vs. how it would look:

# Current way
def meth(num)
yield(num) if block_given?
end

meth 42 { |num| puts num }


# Unified block/proc way
def meth(num, block=nil)
block.call(num) if block
end

meth 42, { |num| puts num }


Nothing too strange, except for that comma in the argument list when
you call the method, since the block is now just a regular parameter.

So when you call 'inject' now, it'd look like this:

sum = [1,2,3].inject 0, { |s, n| s + n }

That comma does look a little funny. Not a big deal, though.

Where's David Black? He usually beats these heretical ideas down pretty fast. :)

Seriously, though, getting rid of the yield keyword, block_given?, the
whole & thing for converting between blocks/procs and the concept of
blocks now being just regular parameters is a big change. The result
would border on a whole different language.

It is _conceptually_ pleasing to unify them. Does it really make our
lives easier?

Dan


Brian Candler

unread,
Jun 30, 2005, 6:05:17 AM6/30/05
to
On Thu, Jun 30, 2005 at 01:59:27AM +0900, Eric Mahurin wrote:
> --- Daniel Brockman <dan...@brockman.se> wrote:
> > Eric Mahurin <eric_m...@yahoo.com> writes:
> >
> > > I think the destructive modification of a class and of an
> > object's
> > > class (making its class a singleton) are the main culprits.
> >
> > However, I ``destructively'' modify standard library classes
> > and
> > modules all the time. This is a major selling point for
> > Ruby.
>
> I'm not going to argue that it is not useful, because it is and
> I use it. I'm just saying that being able to modify a class
> and the (singleton) class of an object at runtime will prohibit
> some amount of optimization within ruby.

But a good inline cache implementation should have pretty small overhead,
and is far easier than attempting to make inferences about the types of
objects.

Ultimately I don't see why a method call a.foo() can't be compiled into
something like this:

/* call a.foo() */

static int md1234;
static VALUE *old_class1234;
static VALUE *fn(void);

if (methods_defined != md1234 ||
(klass = CLASS_OF(a)) != old_class1234)
{
fn1234 = method_find(a, "foo");
md1234 = methods_defined;
old_class1234 = klass;
}
fn1234();

"methods_defined" is a global variable incremented every time a method is
defined, to invalidate all caches. The normal case would be just a few
compares before calling the cached function pointer.

Anyway, there are other things in Ruby which are equally big overheads, and
just as difficult to optimise out. For example,

10.times do
puts "hello"
end

generates a new String object containing "hello" each time round the loop,
which has to be garbage-collected. You can't re-use the same object unless
you can be sure that no references to it have been kept anywhere else.

There are both benefits and costs associated with a highly dynamic language
- but given that CPUs are so cheap, and programmer time is so expensive, I
think it's reasonable to go the Ruby way.

Regards,

Brian.


Daniel Brockman

unread,
Jun 30, 2005, 1:38:58 PM6/30/05
to
Daniel Amelang <daniel....@gmail.com> writes:

> Well, let's look at what our code looks like now vs. how it
> would look:

Good idea.

> # Current way
> def meth(num)
> yield(num) if block_given?
> end
>
> meth 42 { |num| puts num }

Actually, that would have to be either this

meth 42 do |num| puts num end

or this,

meth(42) { |num| puts num }

since this

meth 42 { |num| puts num }

is syntactically treated as this,

meth (42 { |num| puts num })

which makes no sense. (You can argue that it does not make sense to
treat the code as nonsense on purpose, when there is really only one
reasonable interpretation. But then you have this

meth 42.factorial { |num| puts num }

which has two reasonable interpretations, and the one Ruby takes
conflicts with the one needed for the original code to make sense.)

> # Unified block/proc way
> def meth(num, block=nil)
> block.call(num) if block
> end
>
> meth 42, { |num| puts num }
>
> Nothing too strange, except for that comma in the argument list when
> you call the method, since the block is now just a regular parameter.

This is actually an interesting comparison:

meth(42) { |num| puts num }

meth 42, { |num| puts num }

I know everyone will jump the opportunity to scream that the first one
is better in every way. But I don't think it's a clear-cut winner.
(Except when you need to chain more calls onto it --- read on.)

> So when you call 'inject' now, it'd look like this:
>
> sum = [1,2,3].inject 0, { |s, n| s + n }
>
> That comma does look a little funny. Not a big deal, though.

How about this?

average = [1,2,3].inject(0) { |s, n| s + n }.to_f / [1,2,3].size

You'd need to write that like so,

average = [1,2,3].inject(0, { |s, n| s + n }).to_f / [1,2,3].size

unless we kept the old syntax as sugar. On the other hand, I don't
think there would be any problem in doing so. That is, this code

foo(bar) { baz }

would be syntactic sugar for passing `bar' and `{ baz }' to `foo'.

Without the sugar, chaining method calls onto method calls with long
blocks would get pretty ugly. This cutie

moomin snufkin do |a, b, c|
snork.snork.snork.snork
snork.snork.snork.snork
snork.snork.snork.snork
end.frobnicate

would turn into this

moomin(snufkin, do |a, b, c|
snork.snork.snork.snork
snork.snork.snork.snork
snork.snork.snork.snork
end).frobnicate

(I'm assuming `do |x| y end' would be the same as `{ |x| y }'.)

I personally think method calls chained onto long blocks looks bad,
and I try to avoid it myself. But there are probably people who love
doing it, and who would hate it if it started to look even worse.

Note that this would be no problem even without the sugar ---

moomin snufkin do |a, b, c|
snork.snork.snork.snork
snork.snork.snork.snork
snork.snork.snork.snork
end

it would just get an extra comma:

moomin snufkin, do |a, b, c|
snork.snork.snork.snork
snork.snork.snork.snork
snork.snork.snork.snork
end

> Seriously, though, getting rid of the yield keyword, block_given?, the
> whole & thing for converting between blocks/procs and the concept of
> blocks now being just regular parameters is a big change. The result
> would border on a whole different language.

I agree that it is a very big change, but I wouldn't go so far as to
say it would make a different language. Adam is right that Ruby has
been shifting more and more towards this, to the point where Ruby 1.9
can make you think the block syntax looks like an historic quirk.

> It is _conceptually_ pleasing to unify them. Does it really make our
> lives easier?

I would like to know this as well.

The best example I can think of is this,

gizmos.find({ || Gizmo.new :foo => true }) { |x| x.foo? }

which would turn into this,

gizmos.find { || Gizmo.new :foo => true }, { |x| x.foo? }

which I think is an extremely minor improvement.

And what about this syntax?

def foo *args, &block ; ... end

I guess that'd have to become something like this,

def foo *args ; block = args.pop end

which is starting to look suspiciously much like Perl.

Maybe this syntax could be adopted?

def foo a, b, *args, c, d; ... end

That is, at least four arguments, and any extra ones in the the middle
get splatted into `args'. I think it makes sense. Then we'd have

def foo *args, block ; ... end


I think this is an interesting discussion. It's definitely good food
for thought. But, of course, we're just brainstorming.

--
Daniel Brockman <dan...@brockman.se>

Zach Dennis

unread,
Jun 30, 2005, 1:49:10 PM6/30/05
to
Daniel Brockman wrote:

>
> ipv4s.collect! { IPv4Address[@] }
> publics = ipv4s.select { @.public? }
> privates = ipv4s.select { @.private? }
> loopbacks = ipv4s.select { @.loopback? }
>

I disagree. I think this is absolutely horrid looking.

And I think that

ipv4s.collect! { |ip| IPv4Address[x] }

is better. And even if you don't think it adds to readability for single
value blocks I like it for things like...

server.process( connection ) do |msg, msg_type, socket|
# do connection procesing here...
end

Zach


Eric Mahurin

unread,
Jun 30, 2005, 2:11:38 PM6/30/05
to
--- Daniel Brockman <dan...@brockman.se> wrote:

> Maybe this syntax could be adopted?
>
> def foo a, b, *args, c, d; ... end

I want that too. It would be nice for the []= method where the
value is always the last argument. Or any method where you
want optional arguments first or in the middle.

In general, this:

def foo a, b, c=x, d=y, *other, e, f
...
end

should be equivalent to:

def foo a, b, *remaining
e,f = remaining.slice!(-2,2)
c = remaining.empty? ? x : remaining.shift
d = remaining.empty? ? y : remaining.shift
other = remaining
...
end

Want to submit an RCR for this? I've already done my fair
share.

Daniel Brockman

unread,
Jun 30, 2005, 3:11:55 PM6/30/05
to
Zach Dennis <zde...@mktec.com> writes:

> Daniel Brockman wrote:
>
>> ipv4s.collect! { IPv4Address[@] }
>> publics = ipv4s.select { @.public? }
>> privates = ipv4s.select { @.private? }
>> loopbacks = ipv4s.select { @.loopback? }
>
> I disagree. I think this is absolutely horrid looking.

How so? Because of the choice of character? A more mnemonic but less
compatible syntax would be to use an underscore instead of a snail.

loopbacks = ipv4s.select { _.loopback? }

This is mnemonic because `_' suggests ``fill in the blank,'' but less
compatible because it is currently a valid name. Why the lucky stiff
actually uses it, but I doubt if he ever used it inside a block.

Another notation that I like is `<>' from SRFI 26.
(See <http://srfi.schemers.org/srfi-26/srfi-26.html>.)

loopbacks = ipv4s.select { <>.loopback? }

The `<>' is pronounced ``slot''. It also happens to look like a gem.
(The semantics are not exactly those of SRFI 26, but close enough.)

I may actually prefer the underscore; I'm not really sure. I know I
prefer `<>' over `@', and maybe I shouldn't have mentioned the latter.

What do other people think?

> And I think that
>
> ipv4s.collect! { |ip| IPv4Address[x] }
>
> is better.

No comment.

> And even if you don't think it adds to readability for single value
> blocks I like it for things like...
>
> server.process( connection ) do |msg, msg_type, socket|
> # do connection procesing here...
> end

Allow me to raise my voice. OF COURSE IT ADDS READABILITY TO LONG
BLOCKS WITH THREE PARAMETERS. I'm only talking about short blocks
with one parameter. Did you seriously think I was suggesting we
deprecate formal parameters altogether?

--
Daniel Brockman <dan...@brockman.se>

So really, we all have to ask ourselves:
Am I waiting for RMS to do this? --TTN.

Daniel Brockman

unread,
Jun 30, 2005, 3:20:06 PM6/30/05
to
Eric Mahurin <eric_m...@yahoo.com> writes:

> Daniel Brockman <dan...@brockman.se> wrote:
>
>> Maybe this syntax could be adopted?
>>
>> def foo a, b, *args, c, d; ... end
>
> I want that too. It would be nice for the []= method
> where the value is always the last argument.

Yeah, that's a good example. Does anyone have another?

> Or any method where you want optional arguments first or
> in the middle.
>
> In general, this:
>
> def foo a, b, c=x, d=y, *other, e, f
> ...
> end
>
> should be equivalent to:
>
> def foo a, b, *remaining
> e,f = remaining.slice!(-2,2)
> c = remaining.empty? ? x : remaining.shift
> d = remaining.empty? ? y : remaining.shift
> other = remaining
> ...
> end
>
> Want to submit an RCR for this? I've already done my fair share.

Fair enough. I'll wait a few days to see what happens to this thread,
and then I'll probably submit one.

--
Daniel Brockman <dan...@brockman.se>

googlegroups2sucks

unread,
Jun 30, 2005, 8:35:27 PM6/30/05
to
>
> I may actually prefer the underscore; I'm not really sure. I know I
> prefer `<>' over `@', and maybe I shouldn't have mentioned the latter.
>
> What do other people think?


alright, all you party people in the house, take note of my syntax:

when i use the underscore or "_" symbol it's in lieu of what i'd
normally UNDERLINE in a full-blown wordprocessor, because the
bare-bones nature of google's posting mini-app doesn't allow it. when
i want to emphasize the word "duh", i'll type an underscore before and
after, e.g. _duh_. when i want to interject a thought within a
sentence -- like this -- then i use the hyphen symbol.

i'm starting to see more and more so-called journalists using the
underscore instead of the hyphen symbol and thereby confusing my
carefully considered system of syntax. besides, it's driving me up the
wall and it must stop. if you refuse to stop the underscore-for-hyphen
nonsense despite my reasonable request, any goldfish you may or may not
have in your possession will be eaten alive

(p.s. i was thinking of adding a goldfish rape threat in there, but i'm
afraid senator man-on-dog will then be obsessing over man-on-sushi
sexual abnormalities for years henceforth. poor thing has enough to
worry about these days and i'm not that cruel, you know.)

Jim Freeze

unread,
Jul 6, 2005, 12:08:53 AM7/6/05
to
* Florian Frank <fl...@nixe.ping.de> [2005-06-30 13:31:23 +0900]:

> Adam P. Jenkins wrote:
>
> >obj.method_that_takes_two_blocks {|a| ... }, {|b| ...}, third_arg
>

> It is made that way in current Ruby 1.9:
>
> >> def compose(f, g) { |x| f[g[x]] } end
> => nil
> >> h = compose({ |x| 2 * x }, { |x| x + 1 })
> => #<Proc:0x00540dbc@(irb):8>
> >> h[3]
> => 8

Well, this does not appear to be that new. 1.8.2 does the
same, it just requires the 'lambda' keyword:

def compose(f, g)
lambda { |x| f[g[x]] }
end
h = compose(lambda { |x| 2 * x }, lambda { |x| x + 1 })
h[3] #=> 8

However, even with the removal of lambda keyword, I think that
there is a big difference between the 'attached' block and
a block that is just another argument.

meth( {...}, {...}, ...)

is very different from:

meth {...} {...} ...

As has been said before, changing to the former, to get
multiple blocks, will change the way ruby is used
and perceived by developers. And I don't think it
would be for the better.

--
Jim Freeze


0 new messages