Feature #13559
closedChange implementation of Feature #6721
Added by dunrix (Damon Unrix) over 7 years ago. Updated over 7 years ago.
Description
Hi,
please reconsider implementation of feature request #6721 planned for Ruby 2.5.0 .
Instead of introducing new method Object#yield_self
, just reuse existing Object#itself
by taking an optional block argument.
Find it much clearer and more logical solution, not superfluous polluting of API space.
Object#itself
just returns target object, optional block would return alternative value with target object passed as block argument.
Prototyped sol. in Ruby:
class Object
def itself
block_given? ? yield(self) : self
end
end
Not aware of any case, where it would break backward compatibility.
Updated by matz (Yukihiro Matsumoto) over 7 years ago
- Status changed from Open to Feedback
Why?
I don't understand the reason behind your statement 'cleaner and more logical'.
Return values from itself
and yield_self
are semantically different. Unifying them would make static analytics more difficult. Is there any reason over it?
Matz.
Updated by dunrix (Damon Unrix) over 7 years ago
I can see it just as an alternate way of expressing an identity function, not something foreign what would require standalone method. Just an optional modifier of received self. Thus more "logical", from my point of view I admit. Reusing already existing method instead of adding (yet another) new one find "cleaner".
Concerning static analysis objection, I'm not quite sure I understand the point. There are lot of methods in Ruby core, like in Enumerable
, with block as an optional argument. What would be the difference to itself
then ? Associativity precedence for the Ruby parser would be the same. Do you mean some code linters ?
Thank You.
Take care
Updated by zverok (Victor Shepelev) over 7 years ago
To be honest, the selected name for the method dozens of peoples wanted for 5 years looks really bad.
It is like instead of map
Ruby'd had a method named like, I don't know, yield_each_and_return_result
.
I always believed Ruby's method names are carefully selected to produce idiomatic, readable code.
So, I'd vote for itself
too:
url.itself # return itself
url.itself { |u| open(u).read } # return "itself -> fetch from the network"
There are some other good options (listed, for ex., here), that are easy to read, like apply
, as
, chain
, that will produce the code you could read "naturally".
yield_self
is definitely the ugliest of them. It looks like ruby-core devs saying "we don't think we need this method, but OK, if you ask so frequently... take that!"
Updated by nobu (Nobuyoshi Nakada) over 7 years ago
- Is duplicate of Feature #12760: Optional block argument for `itself` added
Updated by nobu (Nobuyoshi Nakada) over 7 years ago
- Description updated (diff)
zverok (Victor Shepelev) wrote:
url.itself # return itself url.itself { |u| open(u).read } # return "itself -> fetch from the network"
It does not seem to return something other than url
"itself".
There are some other good options (listed, for ex., here), that are easy to read, like
apply
,as
,chain
, that will produce the code you could read "naturally".
And let
... but it is used by RSpec.
Or progn
?
Updated by Eregon (Benoit Daloze) over 7 years ago
I agree #yield_self is less than ideal.
To start, it is quite long (10 letters including a underscore) for a very simple method.
In an ideal world, I think #itself with a block doing what #tap does today and #tap doing what #yield_self does would make sense.
But that cannot work with compatibility.
This blog post also made me realize it can be confusing as a method name:
https://bogdanvlviv.github.io/posts/ruby/new-method-kernel-yield_self-since-ruby-2_5_0.html
"#tap yields self to the block and then returns self."
That sounds exactly to what "yield_self" would do.
"#yield_self yields self to the block and then returns the result of the block execution."
#tap already "yields self" and the difference that the block value is returned is absent from the name yield_self.
I am unfortunately not sure what a good name would be.
Maybe #pipe ? (#| conflicts with Array#| so that's not good)
number.pipe { |x| x ** 2 }.next.pipe { |x| x ** 2 }
Fundamentally it works like #map on a single element, but that's already taken by Enumerable#map
and we need something that does not imply collections.
#as and #let seem the most descriptive but do not read well in a chain of method calls.
#itself seems a good compromise.
The current usage like ary.count(&:itself)
to make a block that returns the element
and then expanding it to number.itself { |n| n*n }
makes sense to me.
Instead of having &:itself
be a simple block just returning the argument we can customize it by given #itself a block and return what we want
(which is what most blocks do, use the return value of the block instead of ignoring it).
Updated by Eregon (Benoit Daloze) over 7 years ago
nobu (Nobuyoshi Nakada) wrote:
And
let
... but it is used by RSpec.
Is that actually a problem?
https://github.com/rspec/rspec-core/blob/f4dc5ef5c6bded2b1ec348e856352b60a3e072e9/lib/rspec/core/memoized_helpers.rb#L249-L251
defines it on the example group, so I think it does not clash unless you want to use it inside the ExampleGroup itself, which seems useless (self
already refers to the ExampleGroup).
Updated by zverok (Victor Shepelev) over 7 years ago
url.itself { |u| open(u).read } # return "itself -> fetch from the network"
it does not seem to return something other than url "itself".
well, for ME it is mostly "itself, processed this way".
But I understand that "how I read this code naturally" (considering you are Japanese and I am Ukrainian) is not an easy question :)
Updated by rosenfeld (Rodrigo Rosenfeld Rosas) over 7 years ago
Maybe something like translate, mutate or modify. Or single_map. I also read yield_self as doing the same as tap.
Updated by dunrix (Damon Unrix) over 7 years ago
Eregon (Benoit Daloze) wrote:
In an ideal world, I think #itself with a block doing what #tap does today and #tap doing what #yield_self does would make sense.
But that cannot work with compatibility.
This, exactly.
Just another reminder how important is think decisions through, before acting..
nobu (Nobuyoshi Nakada) wrote:
url.itself { |u| open(u).read } # return "itself -> fetch from the network"
It does not seem to return something other than url "itself".
Yes, result of a block can be anything. I wouldn't expect same object when optional block is passed. Like it already does Object#tap
, unfortunately. It is all about point of view.
Updated by shyouhei (Shyouhei Urabe) over 7 years ago
Well, I know everyone don't like the name yield_self but, it seems that's a separate issue than this one. Can we focus? I guess we need another 5 years to find an "ideal" name of it and that's too off topic to what is requested here.
Updated by MSP-Greg (Greg L) over 7 years ago
Name proposal - cede
url.cede { |u| open(u).read } # return "itself -> fetch from the network"
Updated by nobu (Nobuyoshi Nakada) over 7 years ago
Yet another proposal: https://twitter.com/yancya/status/865070681213386756
just do it.! end