tag:blogger.com,1999:blog-3718956085911858962.post4052962837996628376..comments2023-12-27T14:48:02.113+05:30Comments on Electric Sheep Blog: Ruby blocks gotchasAnonymoushttp://www.blogger.com/profile/11938300811286150164noreply@blogger.comBlogger16125tag:blogger.com,1999:blog-3718956085911858962.post-57774648235963508482011-06-05T19:10:31.552+05:302011-06-05T19:10:31.552+05:30I know it's been a while since this post was f...I know it's been a while since this post was first published, but since people are still commenting on it and noone's suggested possibly the most awesome solution to this, here goes.<br /><br />I know that the point of the post wasn't to implement a profiling/benchmarking framework, but what you're trying to achieve could be implemented using a trivial <a href="http://joyeur.com/2007/05/07/dtrace-for-ruby-is-available/" rel="nofollow">DTrace</a> script => <a href="http://svn.joyent.com/opensource/dtrace/ruby/examples/rb_functime.d" rel="nofollow">rb_functime.d</a>. Since you're on OSX, you should already have libdrace (as well as its dtrace frontend utility), but if you insist on going ruby all the way, there's always <a href="https://github.com/chrisa/ruby-dtrace" rel="nofollow">ruby-dtrace</a>.<br /><br />On a more interesting note, DTrace probes for Ruby were released just a few months before your blog post! :PSaager Mhatrehttps://www.blogger.com/profile/03869587109666583246noreply@blogger.comtag:blogger.com,1999:blog-3718956085911858962.post-57215647285735117652011-06-05T18:57:54.626+05:302011-06-05T18:57:54.626+05:30This comment has been removed by the author.Saager Mhatrehttps://www.blogger.com/profile/03869587109666583246noreply@blogger.comtag:blogger.com,1999:blog-3718956085911858962.post-83686127735407405062011-05-05T18:41:07.132+05:302011-05-05T18:41:07.132+05:30Thanks for the post! I've also written an arti...Thanks for the post! I've also written an article about <a href="http://blog.mostof.it/why-ruby-part-two-blocks-and-closures/" rel="nofollow">Ruby blocks and closures</a> with code examples.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-3718956085911858962.post-91462858907486184652011-01-25T19:29:36.493+05:302011-01-25T19:29:36.493+05:30Still some useful info in this post and comments. ...Still some useful info in this post and comments. Was fighting a similar problem and this helped.<br /><br />In 1.8.7, this was working:<br /><br />... do |*a, &blk|<br />...<br /> send meth, *a, &blk<br /><br />But 1.8.6 didn't like this syntax.<br />After much playing around, I found I needed a "passthrough block" :<br /><br />... do |*a| ...<br />send meth, *a { yield }<br /><br />Hope this comment saves someone else some time.Gerrynoreply@blogger.comtag:blogger.com,1999:blog-3718956085911858962.post-36857811415587886982010-11-07T05:35:36.578+05:302010-11-07T05:35:36.578+05:30This is 3 years after your original post hehe...an...This is 3 years after your original post hehe...anyway..<br /><br />I don't believe this behaviour is an inconsistency. It is a result of blocks being captured by closures and so the 'yield' instead invokes any extant block in the enclosing context.<br /><br />See here: http://banisterfiend.wordpress.com/2010/11/06/behavior-of-yield-in-define_method/Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-3718956085911858962.post-59706951890017473972008-07-31T04:53:00.000+05:302008-07-31T04:53:00.000+05:30I really don't think it can get any simpler th...I really don't think it can get any simpler than this:<BR/><BR/>x = lambda do<BR/> puts 'hello'<BR/> yield<BR/>end<BR/><BR/>x.call { puts 'world' }<BR/><BR/>And the above example still doesn't work with ruby 1.9.0 (2008-07-31 revision 18282) [x86_64-linux].<BR/><BR/>hello<BR/>test.rb:3:in `block in <main>': no block given (yield) (LocalJumpError)<BR/> from test.rb:6:in `call'<BR/> from test.rb:6:in `<main>'<BR/><BR/>So as far as I can see, no, Ruby 1.9 most definitely does not (yet) allow me to IMPLICITLY pass a block to another block, unless we are going to argue that lambdas are some kind of special case.<BR/><BR/>A new thing Ruby 1.9 can do is allow me to EXPLICITLY pass a block. This works in Ruby 1.9 (but didn't work in 1.8)<BR/><BR/>x = lambda do |&block|<BR/> puts 'hello'<BR/> block.call<BR/>end<BR/><BR/>x.call { puts 'world' }<BR/><BR/>Functionally, this is good enough. But the whole business with |&block| is ugly and inconsistent with the use of yield inside methods. Wouldn't allowing the use of yield inside a lambda be nicer? Or am I missing something here?Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-3718956085911858962.post-4378268230727193302008-06-30T00:38:00.000+05:302008-06-30T00:38:00.000+05:30Kudos on tackling a tricky subject with this post....Kudos on tackling a tricky subject with this post. I'd like to offer a couple of "clarifications" which hopefully will help people.<BR/><BR/>The reason the implicit version is faster is because you are repeatedly constructing the Proc every time in the explicit version. <BR/><BR/>If you never access the Proc directly, why add the overhead of constructing an object? This way, you only pay for what you need.<BR/><BR/>I don't really see how this violates the "everything is an object" rule, since as soon as you try to access it, the block becomes an object. :)<BR/><BR/>Also: the problem with passing blocks to blocks is not due to define_method, just blocks. A similar difference exists with default arguments. Method arguments and block arguments will operate the same way (I think) in Ruby 1.9.<BR/><BR/>IMHO, the biggest inconsistency with blocks, especially post 1.9, is one you haven't alluded to here, which is that return behaves differently between Proc.new and lambda.<BR/><BR/>See:<BR/>http://tinyurl.com/29a28d<BR/><BR/>When returning from blocks, passed explicitly or implicitly, return takes you all the way out of the calling method. That is, they behave like Proc.new (which makes sense), not lambda.<BR/><BR/>This is arguably necessary to support the POLS when dealing with inline blocks (say, with #each). You don't expect return to just pop you out of the block, you expect to return from the method. Not sure if that changes in 1.9?<BR/><BR/>Anyway, thanks again for the interesting article!Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-3718956085911858962.post-76456999989860993242008-06-29T15:38:00.000+05:302008-06-29T15:38:00.000+05:30Why are you handrolling your own dubious benchmark...Why are you handrolling your own dubious benchmarking class?Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-3718956085911858962.post-80703488172130092242008-03-15T22:50:00.000+05:302008-03-15T22:50:00.000+05:30Looks like this post is still alive and people rea...Looks like this post is still alive and people read it.. A post that clarifies a lot more things about blocks, closures, procs in ruby is here http://innig.net/software/ruby/closures-in-ruby.rbSudhindra Raohttps://www.blogger.com/profile/07437146809844632919noreply@blogger.comtag:blogger.com,1999:blog-3718956085911858962.post-71896810356638892212008-01-02T21:15:00.000+05:302008-01-02T21:15:00.000+05:30I see four problems with blocks in Ruby 1.8:1. Can...I see four problems with blocks in Ruby 1.8:<BR/><BR/>1. Can't pass a block to a block, thus causing problems with define_method and similar.<BR/><BR/>2. The differences between Proc.new, proc, lambda, and implicit blocks. I have a hard time keeping the differences straight, and try to use only lambda and implicit blocks.<BR/><BR/>3. The performance difference between explicit and implicit block-passing.<BR/><BR/>4. The only way to pass more than one block to a method is to pass (all but one of) them as explicit procs/lambdas.<BR/><BR/>Of these, the first one is definitely fixed in Ruby 1.9, and I think the second one is as well. The third is a quirk of MRI, and it would be worth running some benchmarks in other Ruby implementations (JRuby, Rubinius, IronRuby...). The fourth comes up rarely enough that I have a hard time suggesting a more convenient syntax, even though it annoys me on occasion.<BR/><BR/>In addition, an implicit block can be captured into a Proc object:<BR/><BR/>def foo<BR/> Proc.new<BR/>end<BR/><BR/>bar = foo { |arg| puts "You called me with #{arg}" }<BR/>bar.call(22)<BR/>bar.call(99)<BR/><BR/>I might argue that the implicit block and yield construct in Ruby is a mistake to begin with, but it improves the readability of iteration methods. That one case may or may not justify the complication of two parallel block-passing constructs, however.Gregoryhttps://www.blogger.com/profile/01377458805247260071noreply@blogger.comtag:blogger.com,1999:blog-3718956085911858962.post-84976198416988583272007-11-30T00:46:00.000+05:302007-11-30T00:46:00.000+05:30You're right, I've been investigating something si...You're right, I've been investigating something similar and I stumble upon the same caveats that you did. If someone knows some little known black magic here would be great.AkitaOnRailshttps://www.blogger.com/profile/05539202931163964720noreply@blogger.comtag:blogger.com,1999:blog-3718956085911858962.post-51285518448284908082007-11-27T15:35:00.000+05:302007-11-27T15:35:00.000+05:30re: Blocks violate the 'everything is an object' r...re: Blocks violate the 'everything is an object' rule in Ruby for performance reasons. They only become objects when bound to a variable.<BR/><BR/>I don't think this is correct. Two reasons: 1 - I have read that ruby blocks are not first class objects due to not wanting to expose the implementation to allow for future change. 2 - I'm an old Smalltalk'er. Blocks are first class objects in Smalltalk and a Smalltalk VM of 15 years ago in most cases outperforms a Ruby interpreter of today; including dynamic block dispatches. enjoy!!!Unknownhttps://www.blogger.com/profile/08064528668252467611noreply@blogger.comtag:blogger.com,1999:blog-3718956085911858962.post-9249452399802226812007-11-26T23:50:00.000+05:302007-11-26T23:50:00.000+05:30@anonymous #1 - you're right, it is clearer your w...@anonymous #1 - you're right, it <I>is</I> clearer your way. Thanks!<BR/><BR/>@anonymous #2 - thanks, for the tip, that's worthy of an update to the post.<BR/><BR/>@anonymous #3 - I didn't read it anywhere. What I <I>did</I> read was 'pure OO' and 'everything is an object'. Nothing mentioned exceptions to these rules.Anonymoushttps://www.blogger.com/profile/11938300811286150164noreply@blogger.comtag:blogger.com,1999:blog-3718956085911858962.post-22056268571799956882007-11-26T22:08:00.000+05:302007-11-26T22:08:00.000+05:30I really dont think anyone ever wrote anything abo...I really dont think anyone ever wrote anything about blocks being objects. Where did you read that?Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-3718956085911858962.post-43955431111974085172007-11-26T14:41:00.000+05:302007-11-26T14:41:00.000+05:30Ruby 1.9 block will accept a block as a parameter....Ruby 1.9 block will accept a block as a parameter.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-3718956085911858962.post-58951517545841942942007-11-25T21:59:00.000+05:302007-11-25T21:59:00.000+05:30def foo(*args) blk = args.delete_at(-1) # We know ...def foo(*args)<BR/> blk = args.delete_at(-1) # We know that the last argument <BR/> # is the bound block<BR/> blk.call(args.join(' ')) <BR/>end<BR/><BR/>looks unnecessary clumsy. Why not:<BR/><BR/>def foo(blk, *args)<BR/> blk.call(args.join(' '))<BR/>endAnonymousnoreply@blogger.com