From: Ittay Dror Date: 2008-09-24T17:13:39+09:00 Subject: Re: understanding inheritance and class singleton methods --------------020000000409030108070608 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Brian Candler wrote: >> (or for that matter, specifications how 'splat' behaves >> and the '&' operator before blocks) >> > > Thanks for the response, I was looking more to something along the lines of Ola Bini's post http://ola-bini.blogspot.com/2006/11/nooks-and-crannies-of-ruby.html. He describes there that the splat operator works by first checking if the object has a to_a which allows for some cool tricks. What I want to know is where he got this information from? (digging through the C code?) Ittay > Splat turns an array into an argument list, or vice versa. > > def test1(*args) > p args > end > test1(1,2,3) # prints the array [1, 2, 3] > > def test2(a, b, c) > p a, b, c > end > arg2 = [4,5,6] > test2(*arg2) # prints 4 then 5 then 6 > > You can use splat to "mop up" remaining arguments: > > def test3(a, b, *rest) > p a, b, rest > end > test3(7, 8) # prints 7 then 8 then [] > test3(7, 8, 9) # prints 7 then 8 then [9] > > You can also use it for multiple assignments: > > a, b = *[10, 11] > > and you can use it in blocks: foo { |x,*y| ... } > > Where it gets confusing is special "autosplat" magic which happens for > multiple assignments and blocks where one side is a single array. > > a, b = [10, 11] > p a, b # [10, 11] > > foo = 12, 13, 14 > p foo # [12, 13, 14] > > arr = [ ["foo",1], ["bar",2], ["baz",3] ] > arr.each { |x,y| p x, y } > > p arr.inject(0) { |accum,(k,v)| accum + k.length + v } > > Fortunately, autosplat doesn't happen for method calls, AFAIK. See > http://innig.net/software/ruby/closures-in-ruby.rb (section 4) for more > info. > > As for the & operator, this is pretty simple. It's just a way of turning > the "hidden" block argument into a concrete argument. > > The following two are equivalent: > > def doit1(x,y) > yield x+y > end > > def doit2(x,y,&blk) > blk.call(x+y) > end > > Conversely, if you have an existing proc/lambda type of object, you can > pass it instead of an inline block: > > arr = ["foo", "bar"] > arr.each { |elem| puts "hello #{elem}" } > > callback = lambda { |elem| puts "hello #{elem}" } > arr.each(&callback) > > And hence the blk itself can be passed around as an object. So: > > def doit3(arr) > arr.each { |elem| yield elem } > end > > becomes simply > > def doit4(arr,&blk) > arr.each(&blk) > end > > Personally, I found blocks and yield much easier to understand once I > saw they were just passing a function as an extra argument, and calling > that argument. > -- Ittay Dror Tikal Tikal Project -- -- Ittay Dror --------------020000000409030108070608--