From: Florian Gross Date: 2005-02-15T04:24:58+09:00 Subject: Re: Printing why's (poignant) guide to ruby Ruth A. Kramer wrote: > James Britt wrote: >>Navindra Umanee wrote: >>>If you don't have a clue about the basics like this, you'll soon fail >>>miserably whether you're using Ruby or not. And come-on, who's going >>>to explain yield and blocks to a newbie? >> >>I don't think they are as hard to explain as one might think. (Making >>full use of them is much harder, but getting the essential idea and >>basic syntax and semantics may be pretty straightforward). > > Challenge: Well, how about explaining them (or at least blocks)? > > If you attempt it, how about explaining blocks from the point of view of > an ex-Algol, Pascal, PL/1 programmer, for whom a block is just a way of > grouping several statements together so they can all be executed as a > result of some "test" (like if then else, while do, etc.). Is there > something extra or different about a Ruby block? What? They can have arguments as well. Otherwise they are the general form of the loop/if conditions/code that usually is done via special syntax. An other way of looking at them is as anonymous functions that have access to their definition scope plus a pretty syntax for it. JavaScript has this without the pretty syntax: [1, 2, 3].map(function(item) { return(item * 2) }) means the same as: [1, 2, 3].map { |item| item * 2 } yield() just calls the block that was associated with the current method with the given arguments. This is needed because blocks are usually passed anonymously into methods: # Execute passed block twice and yields index def two_times() yield 0 yield 1 end # Execute passed block twice and yields index as well # This is implemented by forwarding the block to 2.times def two_times(&block) 2.times(&block) end The &foo syntax assigns a block to a special variable in the form of a Proc object meaning it will have .call() and .to_proc() methods and so on in argument lists of method definitions. In argument lists of method invocation it passes the value a variable refers to as the block of a method. On another note it might be interesting to have a look at concatenative languages like Joy. These have something very similar to blocks as well: [1 2 3] [2 *] map What does that code to? C:\dev.svn\ruby>irb -r joy irb(main):001:0> joy = Joy.new => # irb(main):002:0> joy.execute "[1 2 3] [2 *] map"; joy.stack => [[2, 4, 6]] It takes a list and applies the [2 *] predicate to it yielding a new list. Note that Joy is stack based and utilizes reverse polish notation so 2 * pushes a 2 to the stack and multiplies the item that was on top before with it.