I'm against this proposal, IMHO having multiple local variables for the same thing only increases confusion and hurt readability.
If fugafugafuga etc are long method calls/expressions, then they could be saved in local variables outside the then block and that would again be more readable.
Also then is an alias of yield_self which is literally yield self, so I think those semantics would be weird for yield self.
I think then/yield_safe makes sense in a method chain (to not need to break it in multiple lines/break the reading flow).
Extra variables/arguments as you show can just be declared before/outside-the-block as local variables. By definition they are independent of the method chain and so that seems always a better solution.
For your scenarios, as written, I agree with Benoit's #note-2 suggestions. ;) I also agree that core/stdlib #then should only ever yield a single value to its block. However, it's worth noting that multi-parameter blocks will automatically deconstruct a single array arg. E.g:
I most commonly do this when I'm iteratively constructing a one-shot data-munging query in irb/pry. Pipeline segments can output arrays which can be deconstructed by the next segment into multiple args. IMO, it's a great technique for the REPL, but positional parameters can get unwieldy fast. Except for when it's very simple and self-documenting, I prefer to refactor to something that's easier to read before committing or merging.
As a (maybe useful) sidenote, if we'll try to think in "useful atomic constructs" instead of "making existing multi-purpose", Enumerator#with_object is almost what might help here:
3.then.with_object(4){|x,y|p[x,y]}# prints [3, 4] -- as we need, it passes both to the block!#=> 4 -- but returns the object, not the block's result
So, to "return the result", we need to go a long way:
3.then.with_object(4).map{|x,y|x+y}.first# => 7# ...and with several objects, it becomes even more cumbersome:3.then.with_object(4).with_object(5).map{|(x,y),z|x+y+z}.first
I feel like some good atomic solution might be here somewhere, though :)
I do not have any strong opinions either way, but Benoit wrote:
The last example is just:
p.call(honyarara, fugafugafuga, hogehogehoge)
isn't it? And that's a lot more readable IMHO.
Versus:
honyarara.then(fugafugafuga, hogehogehoge, &p)
And I am not sure the .call() is per se more readable.
I agree about the trailing &p part; that one looks a
bit weird. I guess it is just the block. But ignoring
this, if it is merely between .call versus .then,
then I think .then may be quite explicit and perhaps
"more readable", whatever that means. So I am not sure
that .call() is implicitely more readable than .then().
Although, I think one problem is that some ruby authors
write code like:
if condition then
do_something
end
Or something like that. I never used that style, but some
folks used that style in the past. So perhaps it's not
quite so readable if we include the totality of the syntax
out there.
zverok wrote:
3.then.with_object(4).with_object(5).map { |(x, y), z| x + y + z }.first