Hi Kent,

thanks for the lengthy explanation.  Some remarks below.

"Kent Dahl" <kentda / stud.ntnu.no> schrieb im Newsbeitrag
news:3E55E417.32BFBC78 / stud.ntnu.no...
> Robert Klemme wrote:
> > I know that, sorry if I wasn't clear enough. What bugs me is the fact
that
> > the block with a single argument has negative arity, indicating that
there
> > can be more arguments. Why then doesn't the block with two arguments
have
> > arity -2, too?  Or otherwise, why doesn't the block with |a| have arity
1?
>
> I think it has to do with being dynamic so that iterators and blocks can
> be combined more easily.
>
> The fact is that with one block argument, if more values are yielded to
> it, they are collected in an array and passed in the one argument. Thus
> -1 arity. With two block parameters, where would the extra yielded
> values go? We could have treated the last parameters as *args in
> methods, but then too much is going on at once for me atleast. (And
> getting used to blocks took a while for me.)
>
> For a two argument -2 arity block:
>   {|a,*b|}
>
> It might not seem apparent at first, but the special case of the lone
> block parameter helps make Ruby more dynamic, IMHO. Iterating over
> hashes is a rather obvious case:
>   {1=>3, 2=>4}.each{|a,b| puts "#{a}->#{b}"}
> versus
>   {1=>3, 2=>4}.each{|a| puts "#{a.first}->#{a.last}"}
>
> With the latter block, you could have your iterator change a lot more
> without affecting your usage of it. You, the block writer, do not have
> to worry about whether the iterator yields one value (an array with two
> values) or two separate values. And that is yet another bit of freedom
> and dynamicity that makes Ruby stand out. (This kind of magic is
> inherent in return values too, IIRC)

I'm not fully convinced. The reason is, that unless the parameters are just
passed on to some other processing, the block writer must expect multiple
values. In you example, writing

{1=>3, 2=>4}.each{|*a| puts "#{a.first}->#{a.last}"}   # note the "*a"

is not too much overhead but a bit clearer IMHO.  If you write a block that
relies on the some type property (i.e. method present) you have to
explicitely deal with that:

X.each do |a|
  if a.kind_of? String then
    p a if a =~ /foo/
  else
    a.each do |e|
      p e if e =~ /foo/
    end
  end
end

or


X.each do |a|
  a.to_a.each do |e|
    p e if e =~ /foo/
  end
end

or

X.each do |*a|
  a.each do |e|
    p e if e =~ /foo/
  end
end

But I guess it's a lot a matter of taste.

> > It just seemed strange to me that you can have a comma here but no
> > following enumerated element - especially since a block definition with
> > |a,| behaves differently from the one with |a|.
>
> An extra character and visual complexity for those who are really strict
> about what they'll accept from the iterator and bind themselves closer
> to the iterator implementation. Suits them right :-)

:-)

Regards

    robert