David A. Black wrote:
It would also mean that map (and maybe other Enumerable
methods) had one argument syntax and all other iterators had another,
since presumably there’s no general way to make method(:sym) know when
it’s supposed to actually mean method(&:sym).
As you say, it could be extended to other Enumerable methods which
currently don’t take an argument. Maybe useful for:
students.max(:age)
whereas currently you would have to write something like
students.map(&:age).max
or
students.max { |a,b| a.age <=> b.age }.age
[Note that max(&:age) doesn’t work]
Thinking aloud: methods which iterate over a collection would be
expected to replace each elem with elem.send(*args) if given arguments.
And this could be simplified by delegating that job to the ‘each’
method.
class Array
alias :old_each :each
def each(*args, &blk)
if args.empty?
old_each(&blk)
else
old_each { |elem| yield elem.send(*args) }
end
end
end
module Enumerable
def max(*args, &cmp)
cmp ||= Proc.new { |a,b| a<=>b }
first = true
res = nil
each(*args) do |elem| # << NOTE *args passed down
if first
res = elem
first = false
next
end
res = elem if cmp[elem, res] > 0
end
res
end
end
class Person
attr_accessor :name, :age
def initialize(name, age)
@name, @age = name, age
end
end
students = []
students << Person.new(“Alice”,35)
students << Person.new(“Bob”,33)
puts students.max(:age)
But I don’t feel strongly that this is worthwhile, as IMO the language
is more than complicated enough already.
In any case, it was already decided that the “right” way to pass
arguments to an Enumerable was to create a new Enumerator proxy object
for it. That is, even if ‘each’ did take arguments, you’re supposed to
write
students.to_enum(:each, :age).max
rather than max taking arguments and passing them through.