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.
> 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.
In message "Re: yield does not take a block" on Wed, 29 Jun 2005 00:49:17 +0900, James Britt <jame...@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?
> In message "Re: yield does not take a block" > on Wed, 29 Jun 2005 00:49:17 +0900, James Britt <jame...@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?
Yukihiro Matsumoto <m...@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.
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].
> 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.
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
> 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 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...
> * 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...
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
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 <jame...@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?).
Anyway, the programmer should be saved from fooling himself inventing more and more complicated constructions.
> In article > <20050628215637.45029.qm...@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
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.
> 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.
> 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 <jame...@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.
> > 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.
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.
Yukihiro Matsumoto <m...@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.
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?
Eric Mahurin wrote: > --- Yukihiro Matsumoto <m...@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 >> <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.
> 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.
Note though that yield and &c.call work quite differently. This has for example performance implications.
> 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
Eric Mahurin wrote: > --- Robert Klemme <bob.n...@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)
> Eric Mahurin wrote: > > --- Robert Klemme <bob.n...@gmx.net> wrote: > > 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)
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.
____________________________________________________ Yahoo! Sports Rekindle the Rivalries. Sign up for Fantasy Football http://football.fantasysports.yahoo.com
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.