[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

yield does not take a block

Daniel Brockman

6/28/2005 8:37:00 AM

46 Answers

Nakada, Nobuyoshi

6/28/2005 10:40:00 AM

0

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

6/28/2005 3:32:00 PM

0

Hi,

In message "Re: yield does not take a block"
on Tue, 28 Jun 2005 17:37:06 +0900, Daniel Brockman <daniel@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_b

6/28/2005 3:49:00 PM

0

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.ru... - The Ruby Documentation Site
http://www.r... - News, Articles, and Listings for Ruby & XML
http://www.rub... - The Ruby Store for Ruby Stuff
http://www.jame... - Playing with Better Toys


Yukihiro Matsumoto

6/28/2005 4:19:00 PM

0

Hi,

In message "Re: yield does not take a block"
on Wed, 29 Jun 2005 00:49:17 +0900, James Britt <james_b@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_b

6/28/2005 4:29:00 PM

0

Yukihiro Matsumoto wrote:
> Hi,
>
> In message "Re: yield does not take a block"
> on Wed, 29 Jun 2005 00:49:17 +0900, James Britt <james_b@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?

No. Good strange.


James


Daniel Brockman

6/28/2005 5:30:00 PM

0

Yukihiro Matsumoto

6/28/2005 7:46:00 PM

0

Hi,

In message "Re: yield does not take a block"
on Wed, 29 Jun 2005 02:30:05 +0900, Daniel Brockman <daniel@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

6/28/2005 8:18:00 PM

0



--- Yukihiro Matsumoto <matz@ruby-lang.org> wrote:

> Hi,
>
> In message "Re: yield does not take a block"
> on Wed, 29 Jun 2005 02:30:05 +0900, Daniel Brockman
> <daniel@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.


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


Ryan Leavengood

6/28/2005 8:50:00 PM

0

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

6/28/2005 9:12:00 PM

0

* Ryan Leavengood <mrcode@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