Robert Klemme wrote:
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.
And alot more symmetric with methods, which is yet another argument for
the asterisk. But after having grown used to it, I still don’t want to
have to use the * here.
If you write a block that
relies on the some type property (i.e. method present) you have to
explicitely deal with that:
Do I? First of all, there is the issue of duck typing, so I wouldn’t
test like this anyway. What I am advocating is not that yield 1 and
yield 1,2,3 is interchangable(which would require explicit testing of
the type), but that yield 1,2,3 and yield [1,2,3] are.
That doesn’t seem like a big thing at first, until you suddenly find the
need to extend the returned values for some special cases. I’ll use
something I wrote up to convince myself after writing the previous post.
Lets say we have been yielding two values, key and value, such as from a
Hash, yielding it with “yield key, value”. Then suddenly yet another
property is needed. I could change values to [value, new_property] and
extract the value when iterating normally and yielding all including
new_property in a special method. This way lies madness, and it isn’t
particularly OO either. So lets write a simple Hash that uses a concrete
object for the entry pair key-value:
class Entry < Array
end
class MyHash
def initialize
@entries =
end
def
# strange hashing magic
end
def insert(key, value)
e = Entry.new
e << key
e << value
@entries << e
end
def each
@entries.each{|e| yield e}
end
end
m = MyHash.new
m.insert( “a”, “Alfa” )
m.insert( “b”, “Beta” )
m.each{|e| p e.type } # I care about entry metadata
m.each{|k,v| p k.type, v.type } # I don’t, gimme the content!
Those two calls to each are what I’m all about. If I want access to all
of the object, and do the cumbersome lookup, and have access to whatever
extra properties that I decide to add to Entry, then I only write one
block parameter. If I only want the key and value from the entry, I use
two. The control is in the recieving block, and I do not have to
consider both cases in one block; I choose which way to attack what is
yielded by how I define the block.
Now, this doesn’t look all to wrong with the *a version does it? Well,
it blows up with *a. Remember how methods use * to pack and unpack
arguments in an Array? The line
m.each{|*e| p e.type } # But I cared about entry metadata! sob
turns out to turn my stuff inside out, removing my dear Entry class and
rewrapping everything in a new Array. Should the * be allowed to have a
differing behaviour and take over for the lone block argument? Doing so
would make block arguments more like method arguments, removing one
surprise, but introducing another: *e can turn out to be something
different from an Array with blocks. Net gain, zilch.
But I guess it’s a lot a matter of taste.
Aye, and like fine wine, its an aquired one at that 
Disclaimer: I hope the above makes somewhat sense and isn’t too wrong in
parts. I haven’t slept too well so my head is everywhere.
···
–
([ Kent Dahl ]/)_ ~ [ http://www.stud.ntnu.no/~kentda/ ]/~
))_student/(( _d L b_/ NTNU - graduate engineering - 5. year )
( __õ|õ// ) )Industrial economics and technological management(
_/ö____/ (_engineering.discipline=Computer::Technology)