From: "David A. Black" Date: 2004-08-12T21:46:45+09:00 Subject: Re: [proto-rcr] Blocks: default arguments and method signatures Hi -- On Thu, 12 Aug 2004, Sam McCall wrote: > I thought I'd post these ideas here, since last time I wrote up an RCR > and then got told that the issue had already been addressed in plans for > Ruby 2. Also, some ideas I'm pretty happy with, some are quite > radical/provocative. Hopefully those latter bits are somewhat > independent, which ones do you like? (if any ;) > So please let me know if I'm missing something, or this could be done > better. > > 1) Default arguments for &block > Often a method performs some simple reasonably useful behaviour if no > block is given, otherwise it lets the block do something more useful. > For example: > > def transform_values(array) > out=[] unless block_given? > array.each { |value| > # calculations... > if block_given? > yield value,newvalue > else > out<< newvalue > end > } > out > end > > I propose &block could take a default argument, probably of the form > &block={|x| foo}, but I could live with &block=proc {|x| foo}. > block_given? would return *false* if the default value was used (I'm > flexible on this bit). > The default block would be scoped *inside* the method. > That example would become: > > def transform_values(array) &block={|val,newval| out<< newval} I can definitely see the point of the default assignment, but I think you're changing too much here by putting it outside the arglist. &block is a special argument, I know, but it's still part of the list. I also don't like the forward reference to a local variable here (out). When you get to this: > out=[] unless block_given? it really feels a bit convoluted. > array.each { |value| > #calculations... > yield value,newvalue I think block.call(value,newvalue) would be clearer here, since yield really means that the business is being done by switching control to a block provided in association with the method call. I understand that you're sort of retro-fitting your default block to play that role, but I still think it's better to save yield for the traditional yield scenario. > } > end You're not returning 'out'? And if you are, are you sure you want the return value to be nil if a block was given? Just for completeness, here's a present-day version that returns the original array if a block is given, and otherwise returns the accumulated transformations: def transform_values(array,&block) res = if block then array else [] end block ||= lambda {|val,newval| res << newval } array.each do |value| newvalue = value * 10 block.call(value, newvalue) end return res end # A couple of test runs: p transform_values([1,2,3]) p transform_values([1,2,3]) {|x,y| puts "#{x} => #{y}" } # Output [10, 20, 30] 1 => 10 2 => 20 3 => 30 [1, 2, 3] David -- David A. Black dblack@wobblini.net