Daniel Amelang said:
Well, let's look at what our code looks like now vs. how it
would look:
Good idea.
# Current way
def meth(num)
yield(num) if block_given?
end
meth 42 { |num| puts num }
Actually, that would have to be either this
meth 42 do |num| puts num end
or this,
meth(42) { |num| puts num }
since this
meth 42 { |num| puts num }
is syntactically treated as this,
meth (42 { |num| puts num })
which makes no sense. (You can argue that it does not make sense to
treat the code as nonsense on purpose, when there is really only one
reasonable interpretation. But then you have this
meth 42.factorial { |num| puts num }
which has two reasonable interpretations, and the one Ruby takes
conflicts with the one needed for the original code to make sense.)
# Unified block/proc way
def meth(num, block=nil)
block.call(num) if block
end
meth 42, { |num| puts num }
Nothing too strange, except for that comma in the argument list when
you call the method, since the block is now just a regular parameter.
This is actually an interesting comparison:
meth(42) { |num| puts num }
meth 42, { |num| puts num }
I know everyone will jump the opportunity to scream that the first one
is better in every way. But I don't think it's a clear-cut winner.
(Except when you need to chain more calls onto it --- read on.)
So when you call 'inject' now, it'd look like this:
sum = [1,2,3].inject 0, { |s, n| s + n }
That comma does look a little funny. Not a big deal, though.
How about this?
average = [1,2,3].inject(0) { |s, n| s + n }.to_f / [1,2,3].size
You'd need to write that like so,
average = [1,2,3].inject(0, { |s, n| s + n }).to_f / [1,2,3].size
unless we kept the old syntax as sugar. On the other hand, I don't
think there would be any problem in doing so. That is, this code
foo(bar) { baz }
would be syntactic sugar for passing `bar' and `{ baz }' to `foo'.
Without the sugar, chaining method calls onto method calls with long
blocks would get pretty ugly. This cutie
moomin snufkin do |a, b, c|
snork.snork.snork.snork
snork.snork.snork.snork
snork.snork.snork.snork
end.frobnicate
would turn into this
moomin(snufkin, do |a, b, c|
snork.snork.snork.snork
snork.snork.snork.snork
snork.snork.snork.snork
end).frobnicate
(I'm assuming `do |x| y end' would be the same as `{ |x| y }'.)
I personally think method calls chained onto long blocks looks bad,
and I try to avoid it myself. But there are probably people who love
doing it, and who would hate it if it started to look even worse.
Note that this would be no problem even without the sugar ---
moomin snufkin do |a, b, c|
snork.snork.snork.snork
snork.snork.snork.snork
snork.snork.snork.snork
end
it would just get an extra comma:
moomin snufkin, do |a, b, c|
snork.snork.snork.snork
snork.snork.snork.snork
snork.snork.snork.snork
end
Seriously, though, getting rid of the yield keyword, block_given?, the
whole & thing for converting between blocks/procs and the concept of
blocks now being just regular parameters is a big change. The result
would border on a whole different language.
I agree that it is a very big change, but I wouldn't go so far as to
say it would make a different language. Adam is right that Ruby has
been shifting more and more towards this, to the point where Ruby 1.9
can make you think the block syntax looks like an historic quirk.
It is _conceptually_ pleasing to unify them. Does it really make our
lives easier?
I would like to know this as well.
The best example I can think of is this,
gizmos.find({ || Gizmo.new :foo => true }) { |x| x.foo? }
which would turn into this,
gizmos.find { || Gizmo.new :foo => true }, { |x| x.foo? }
which I think is an extremely minor improvement.
And what about this syntax?
def foo *args, &block ; ... end
I guess that'd have to become something like this,
def foo *args ; block = args.pop end
which is starting to look suspiciously much like Perl.
Maybe this syntax could be adopted?
def foo a, b, *args, c, d; ... end
That is, at least four arguments, and any extra ones in the the middle
get splatted into `args'. I think it makes sense. Then we'd have
def foo *args, block ; ... end
I think this is an interesting discussion. It's definitely good food
for thought. But, of course, we're just brainstorming.