Block.call vs. yield

Two arguments for accepting Proc#yield.

A. Arguing against David’s logic (above)

···

On Saturday, April 26, 2003, 10:03:28 PM, dblack wrote:

In a ‘yield’, the block is being yielded to – it is not, itself,
yielding control. Therefore, what you’d really need, to describe a
yield in terms of the block as a receiver, would be something like:

blk.be_yielded_to

which I’m not advocating, of course; it’s just that

blk.yield

suggests that the block is performing an action described as
'yield’ing, which I don’t think it is.


The same argument applies to Proc#call.

p = proc { |x| x + 3 }
p.call(2) # → 5

Really, a more accurate name would be

p.be_called(2)

In David’s language:

“blk.call” suggests that the block is performing an action described
as 'call’ing, which I don’t think it is.

B. Arguing positively from first principles

The two methods following are functionally equivalent.

def foo1(n, &block)
block.call(n+1)
end

def foo2(n)
yield n+1
end

They are effectively the same, and they both make sense. But what is
that “yield” really? It’s like a method call with an implicit
receiver. The receiver is the block passed to the method call.

If we are happy with “yield” (the keyword) being an implicit method
call, why can’t we allow it to be an explicit method call, in which it
does the same thing?

Concluding notes

The keyword “yield” was probably borrowed from another language, but
it helps to consider what it really means, which is “produce”. This
makes sense as a keyword because it is producing a value, or list of
values, to be consumed by an anonymous block.

Therefore, “yield” is a special case issue of “giving way” (another
meaning of yield) to the parent method, temporarily. It really is the
perfect name for what it does. But it’s not the perfect name to
describe mvalues, avalues and parameters. That’s where David et al
have a good point.

But it’s a different point from what is discussed (twice) above.

Cheers,
Gavin

Yukihiro Matsumoto wrote:
vocating, of course; it’s just that

blk.yield

Anyway, what is your opinion to make them better?

invoke ?

Here are a few ideas about names. They maybe all wrong since I may have
missed the point entirely. (I’m very new at Ruby.) If that is the case,
just cast them out.

blk.take
blk.accept
blk.acquire
blk.adopt
blk.assume
blk.borrow
blk.claim
blk.demand
blk.engage
blk.lease

JF

···

On Sat, 26 Apr 2003 23:26:14 +0900, Yukihiro Matsumoto matz@ruby-lang.org wrote:

Hi,

In message “Re: block.call vs. yield” > on 03/04/26, dblack@superlink.net dblack@superlink.net writes:

In a ‘yield’, the block is being yielded to – it is not, itself,
yielding control. Therefore, what you’d really need, to describe a
yield in terms of the block as a receiver, would be something like:

blk.be_yielded_to

which I’m not advocating, of course; it’s just that

blk.yield

suggests that the block is performing an action described as
'yield’ing, which I don’t think it is.

Also, the use of ‘yield’ as shorthand for ‘call with certain
semantics’ (if I’m understanding that correctly) seems very obscure
to me. This would be very hard to explain to someone learning Ruby
(“The block isn’t actually yielding control; the method is called
‘yield’ because elsewhere in the language there’s something called
‘yield’ that has the same calling semantics…”).

Hmm, understandable. It’s not obscure for me at all though.
Actually, as a Japanese, I don’t use the word “yield” for any other
purpose, so that my feeling is far different from yours.

Anyway, what is your opinion to make them better?

Naming is the key of problem solving. If you choose good name, you
will succeed.

  					matz.

  • eval.c (proc_invoke): Proc#call gives avaules, whereas
    Proc#yield gives mvalues.
···

----- Original Message -----
From: “ts” decoux@moulon.inra.fr


Should I just not even ask what’s an “avalue” and an “mvalue”?

:slight_smile:

That part isn’t in the new ri.

Chris

Hi –

From: dblack@superlink.net
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Sent: Saturday, April 26, 2003 10:13 AM
Subject: Re: block.call vs. yield

Maybe something like call_with_… or call_as… ? (Not sure what the
… would be.)

call_as_block perhaps?? or just call_block ?

Another thought:

If Proc#call has method-like semantics, perhaps what’s needed is a
method with block-like semantics – namely, Block#call. That, of
course, would also mean “Block” would be needed :slight_smile:

But in fact, there is a certain logic to this, I think:

pr = Proc.new {|x,y| puts x,y}
pr.call(1,2) # => 1\n2\n
pr.call(1) # => error

but then:

pr.to_block.call(1) # => 1\nnil\n

Also, of course:

b = Block.new {|x,y| puts x,y}
b.call(1,2,3,4,5) # => 1\n2\n

Quick and probably badly designed implementation:

class Block < Proc
private; def callback(*args); yield(args); end
public; def call(*args); callback(*args,&self); end
end

class Proc
def to_block
Block.new &self
end
end

David

···

On Sun, 27 Apr 2003, Hal E. Fulton wrote:

----- Original Message -----


David Alan Black
home: dblack@superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

I am in that group. I have been caught out several times by writing

mything.each do |thing|

end

where mything is a hash of objects, and I just get a confusing error message
somewhere later on in my code, perhaps much later.

If you want to match exactly one argument you can write

… do |thing,|

but I never remember to do that.

Regards,

Brian.

···

On Mon, Apr 28, 2003 at 06:06:36PM +0900, Gavin Sinclair wrote:

If you want to take a step back and look for a unifying concept, which
I applaud, then I think the only choice is to abolish “yield
semantics”. The splat (*) operator allows you to achieve the same
result anyway - when you want to.

hash.each do |o|
# Array === o
end

is annoying to some people. They would rather have an error (wrong
number of parameters) than an unexpected value being assigned to the
parameter, and I sympathise.

Hi –

···

On Mon, 28 Apr 2003, Gavin Sinclair wrote:

If you want to take a step back and look for a unifying concept, which
I applaud, then I think the only choice is to abolish “yield
semantics”. The splat (*) operator allows you to achieve the same
result anyway - when you want to.

I’m not seeing why that’s the only choice. How about finding a
better name? :slight_smile:

David


David Alan Black
home: dblack@superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

Hi –

The same argument applies to Proc#call.

p = proc { |x| x + 3 }
p.call(2) # → 5

Really, a more accurate name would be

p.be_called(2)

In David’s language:

“blk.call” suggests that the block is performing an action described
as 'call’ing, which I don’t think it is.

There’s some precedent for receivers as “direct objects” of the verbs
in their methods (e.g., Array#pack/flatten/sort,
String#crypt/capitalize/center, etc.). So in that one can “call a
Proc”, one can imagine Proc#call. But one does not “yield a Proc”.
If anything, one yields parameters to a Proc.

The two methods following are functionally equivalent.

def foo1(n, &block)
block.call(n+1)
end

def foo2(n)
yield n+1
end

They are effectively the same, and they both make sense. But what is
that “yield” really? It’s like a method call with an implicit
receiver. The receiver is the block passed to the method call.

If we are happy with “yield” (the keyword) being an implicit method
call, why can’t we allow it to be an explicit method call, in which it
does the same thing?

If it’s an implicit method call (which isn’t how I would describe it,
but anyway), the phantom receiver would be, I think, the current
method. I.e., it’s more like: I (the method) am going to yield
control to a block, rather than: I (the block) am going to yield, or
be yielded.

This isn’t an exact match with other constructs – but it isn’t
supposed to be. That’s why yield is so cool :slight_smile: It’s also another
reason I like the idea of isolating the ‘yield’ keyword.

The keyword “yield” was probably borrowed from another language, but
it helps to consider what it really means, which is “produce”. This
makes sense as a keyword because it is producing a value, or list of
values, to be consumed by an anonymous block.

I think what it really means is “yield” – i.e., yield control, at
this point in the program.

Therefore, “yield” is a special case issue of “giving way” (another

Yeah, that :slight_smile:

meaning of yield) to the parent method, temporarily. It really is the

(Actually to the block, from the method.)

perfect name for what it does. But it’s not the perfect name to
describe mvalues, avalues and parameters. That’s where David et al
have a good point.

The question then becomes: why press it into service for that?
Electrons are cheap :slight_smile:

David

···

On Mon, 28 Apr 2003, Gavin Sinclair wrote:


David Alan Black
home: dblack@superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

I’m curious why you feel we need a method to do this. Why is the yield
keyword insufficient?

Paul

···

On Sun, Apr 27, 2003 at 12:24:53AM +0900, Yukihiro Matsumoto wrote:

Iff you can name it a good name.

The name “yield” tells you “how different from #call”. This is
important. Other names (e.g. invoke) tells you the fact it’s
different from #call, but not how.

But there still be possibility for the better name.

invoke ?

If someone read the source he'll have problems to understand what do ruby

static VALUE
proc_call(proc, args)
    VALUE proc, args; /* OK */
{
    return proc_invoke(proc, args, Qtrue, Qundef);
}

static VALUE
proc_yield(proc, args)
    VALUE proc, args; /* OK */
{
    return proc_invoke(proc, args, Qfalse, Qundef);
}

#invoke will call proc_invoke with Qfalse :-)))

p.s.: #invoke seems fine to me

Guy Decoux

Should I just not even ask what's an "avalue" and an "mvalue"?

"avalue" = "array value"

"mvalue" = "multi(?) value"

You'll find in ruby mrhs, mlhs, massign for 'a, b, c = d, e, f' and
variables given to a block '|a, b, c|'

That part isn't in the new ri.

it was written before the modification

Guy Decoux

And that’s very ugly, IMO.

Gavin

···

On Monday, April 28, 2003, 7:17:24 PM, Brian wrote:

If you want to match exactly one argument you can write

… do |thing,|

but I never remember to do that.

I can’t think of anything other than:

blk.call_but_collapse_surplus_arguments_into_the_final_parameter_as_an_array

:slight_smile:

This concept does not, AFAIK, map to any short name. Nor is it
endorsed by any theory in computer science. I’d be interested to know
the origin and purpose of “yield semantics”, but I doubt they derive
from some “best practice”.

My conclusion: yield semantics are unlikely to ever be known as
anything other than yield semantics :slight_smile: It has nothing to do with
yielding; it’s just, as you said, historical.

Gavin

···

On Monday, April 28, 2003, 8:13:01 PM, dblack wrote:

Hi –

On Mon, 28 Apr 2003, Gavin Sinclair wrote:

If you want to take a step back and look for a unifying concept, which
I applaud, then I think the only choice is to abolish “yield
semantics”. The splat (*) operator allows you to achieve the same
result anyway - when you want to.

I’m not seeing why that’s the only choice. How about finding a
better name? :slight_smile:

Hmmmm, I think you’re right.

···

On Monday, April 28, 2003, 8:30:01 PM, dblack wrote:

[big fat snip]

Hi,

···

In message “Re: block.call vs. yield” on 03/04/29, Paul Brannan pbrannan@atdesk.com writes:

I’m curious why you feel we need a method to do this. Why is the yield
keyword insufficient?

Some, for example dRuby, requires the method.

						matz.

Hi,

···

In message “Re: block.call vs. yield” on 03/04/26, ts decoux@moulon.inra.fr writes:

If someone read the source he’ll have problems to understand what do ruby

static VALUE
proc_call(proc, args)
VALUE proc, args; /* OK */
{
return proc_invoke(proc, args, Qtrue, Qundef);
}

static VALUE
proc_yield(proc, args)
VALUE proc, args; /* OK */
{
return proc_invoke(proc, args, Qfalse, Qundef);
}

#invoke will call proc_invoke with Qfalse :-)))

:wink: In that case, I will rename those functions.

						matz.

Hi,

···

In message “Re: block.call vs. yield” on 03/04/28, Gavin Sinclair gsinclair@soyabean.com.au writes:

… do |thing,|
but I never remember to do that.

And that’s very ugly, IMO.

I know, but I have to solve them one at a time. FYI, I proposed
block parameter that works like function arguments, but many hated
it because of its ugliness. Design is a hard thing indeed.

						matz.

Hi –

···

On Tue, 29 Apr 2003, Yukihiro Matsumoto wrote:

Hi,

In message “Re: block.call vs. yield” > on 03/04/29, Paul Brannan pbrannan@atdesk.com writes:

I’m curious why you feel we need a method to do this. Why is the yield
keyword insufficient?

Some, for example dRuby, requires the method.

I know there must be an obvious answer to this, but… what is an
example of something that requires this (specifically, requires that
it be added to the core language)?

David


David Alan Black
home: dblack@superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

… do |thing,|
but I never remember to do that.

And that’s very ugly, IMO.

I know, but I have to solve them one at a time. FYI, I proposed
block parameter that works like function arguments, but many hated
it because of its ugliness. Design is a hard thing indeed.

I certainly agree there :slight_smile:

I imagine ‘yield semantics’ were put in the language to solve some problem,
or make it work better in some circumstances; do you have an example of
that?

If I understand rightly, the ‘yield semantics’ mean that:

>a>  given 0 arguments  => a = nil
     given 1 argument   => a = arg
     given 2+ arguments => a = [arg1, arg2, ...]

That gives a slightly odd sort of polymorphism - to be useful, the block
must be able to cope with either a single unwrapped object or an array which
wraps multiple objects.

Suppose block parameters worked like function arguments - how would life be
worse? (ignoring backwards compatibility)

Regards,

Brian.

···

On Mon, Apr 28, 2003 at 07:02:43PM +0900, Yukihiro Matsumoto wrote:

In message “Re: block.call vs. yield” > on 03/04/28, Gavin Sinclair gsinclair@soyabean.com.au writes:

Hi,

···

In message “Re: block.call vs. yield” on 03/04/29, dblack@superlink.net dblack@superlink.net writes:

I know there must be an obvious answer to this, but… what is an
example of something that requires this (specifically, requires that
it be added to the core language)?

Proc#yield cannot be implemented using Proc#call, and other way
around. This is good enough reason for me.

						matz.