From: Sam McCall Date: 2004-08-12T22:51:19+09:00 Subject: Re: [proto-rcr] Blocks: default arguments and method signatures Robert Klemme wrote: >>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. > > > I like that idea, but block_given? but I don't like the return value for > block_given?. OTOH, if you declare &b with a default parameter you'll > always have a block and thus would never query. Thus the reason block_given? should return false when the default value was taken: it might as well, as the other sense is entirely useless ;) It would be needed to detect whether to do some setup for the default block (for non-default blocks this is done in the scope of the caller). Of course this doesn't work as you point out. > Addional note: you can achieve the same with > b = lambda {|x| foo} unless b Yeah. It seems a little more expressive/consistent/natural to have it as a default variable (for the same reasons we have defaults rather than optionals in ruby), but that probably is nice enough. >>That example would become: >> >>def transform_values(array) &block={|val,newval| out<< newval} >>out=[] unless block_given? >>array.each { |value| >>#calculations... >>yield value,newvalue >>} >>end > > I doubt that this will work: because of the scoping 'out' cannot be known > in the block: Erk. You're right. I did test it - in irb, having used the name "out" a few pages up ;-) Seems like a showstopper. >>2) Taking anonymous block parameter, making it part of the signature >>Two issues: >> a) If block default values are adopted, then giving the block a >> name might sometimes seem silly, as the name's never used. >> See the above example, "block" is never referenced. >>b) No way to specify taking a block as part of method signature. >> Descrptive signatures are good: >> * See syntax in auto-docs/code without reading whole thing >> * See syntax in auto-docs/code when there's no comments >> * Flag errors at start of method, and on every invocation. >> >>Proposal: allow "&" in place of "&block": >>def foo & (or maybe: def foo &!) >>As soon as the method is called, raises an error if no block is >>given (similar to wrong number of args) >>def foo &? (or maybe: def foo &) >>No change from current behaviour of def foo, but denotes that >>this method can take a block and might use it if given. >>(MAYBE:) >>def foo &block! or >>def foo &!block or >>replace current meaning(!) of: def foo &block >>This method is required to take a block, not passing a block >>raises an error. >>def foo &block or >>def foo &block? or >>def foo &?block, etc >>Current meaning of &block. > > > I don't like this one because it's not much of an improvement. As far as > I can see the only advantage is the automated block check on invocation. Improvements as I see them (excluding default-block-args stuff): People reading the documentation/code can see the syntax without reading the whole description/method body. This is important to me, maybe not to others. Might be partially soluble by getting rdoc to look for yields. Detect errors sooner. My biggest problem with Ruby is errors that aren't flagged till runtime. In scripts where there's 5 minutes of startup time, this makes debugging SLOW. Fix a bug, wait 5 minutes, fix another bug, wait 5 minutes... Detect improbable errors. A method processes some data and takes a block which handles erroneous data in some customised way. Not passing a block doesn't cause an error if all you data is valid. >>My preferred syntax in a throw-everything-away-for-Ruby2 scenario: >>Named block Anonymous block >>Disallowed def foo def foo >>Optional def foo &block? def foo &? >>Defaulted def foo &block={} def foo &={} >>Compulsory def foo &block def foo & >> >>My preferred syntax in a backwards-compatible scenario: >>Named block Anonymous block >>Disallowed - - >>Optional def foo &block def foo &? >>Defaulted def foo &block={} def foo &={} >>Compulsory def foo &block! def foo &! > > Sorry, I don't understand these. Can you elaborate, please? Er. My mailer showed tabs as 8 spaces, and then expanded them to 4, or something :-\ It was *meant* to be a table showing how you would define a no-args function called foo that took no block/optional block/optional block with default/compulsory block, which would be named/anonymous. My (updated) preferred syntax overall (ignoring compatibility): Disallowed block: def foo Optional anonymous block: def foo &=nil Optional named block: def foo &block=nil Compulsory anonymous block: def foo & Compulsory named block: def foo &block [Very simple default args (the default must be a proc object, block_given? is just "not block.nil?") could be unintrusively done, and would probably only be useful for the =nil syntax, and for completeness. I think it's worth it ;-)] My (updated) preferred syntax overall (backwards compatible): Disallowed block: Optional anonymous block: def foo OR: def foo & Optional named block: def foo &block Compulsory anonymous block: def foo &! Compulsory named block: def foo &block! Thanks for the input, I knew I would have missed something :-) Sam