Feature #10394
closedAn instance method on Enumerator that evaluates the block under with self being the block variable.
Description
Background
There has been desire to omit the | |
and the explicit receiver in a block used with an enumerator or an enumerable. Currently, when the content of the block is a single method that takes no argument, symbol-to-proc is used with the &
syntax so that:
["foo", "bar"].map{|s| s.upcase}
can be written as:
["foo", "bar"].map(&:upcase)
There has repeated been proposals (#8987, #9076, #10318) that express this desire to do this even when the block involves a method chain or a method with arguments like the following:
["foo", "bar"].map{|s| s.concat("ber")}
[" foo ", "\tbar\n"].map{|s| s.strip.upcase}
Focus has been on modifying how a block is passed to the enumerable/enumerator, and there has not been consensus on how the syntax should be.
Proposal
Unlike the earlier proposals, I suggest that there should be an instance method on Enumerator
, let's say Enumerator#as_self
, that evaluates the block each time with self
being the block variable that would be passed otherwise. With such method, the cases above would be written like this:
["foo", "bar"].map.as_self{concat("ber")}
[" foo ", "\tbar\n"].map.as_self{strip.upcase}
This adds no modification to the syntax, it just requires a new method Enumerator#as_self
to be implemented. I consider this method being along the lines of Enumerator#with_index
, Enumerator#with_object
; it intervenes between an enumerator (related to a block-taking method) and a block, and let the block-taking method work in a modified way.
It resembles instance_eval
, but is different in that it assigns to self
what would be a block variable (which changes for each iteration), instead of assigning the receiver.
Updated by matz (Yukihiro Matsumoto) almost 9 years ago
- Status changed from Open to Feedback
I like the idea itself. But I don't think as_self
is a good name.
Any other name proposal? Anyone?
Matz.
Updated by gogotanaka (Kazuki Tanaka) almost 9 years ago
Sounds good for me.
(Actually I face the difficulties to implement #10318 ... and it's painful)
I just come up with...
#as
#as_arg(s)
#through
#member
.... ; (
And I'd be happy to call method which needs more than 2 args, if it could be.
just idea.
Updated by sawa (Tsuyoshi Sawada) almost 9 years ago
If the name is less than five characters, then it would need less typing than the original form, (i.e., five-letter name .xxxxx{foo}
would require as much typing as {|x| x.foo}
), so there would be more motivation for using this method. It may be good to use some preposition:
["foo", "bar"].map.by{upcase}
["foo", "bar"].map.by{concat("ber")}
[" foo ", "\tbar\n"].map.by{strip.upcase}
If one wants to go with a non-letter method name, |
may be a candidate:
["foo", "bar"].map.|{upcase}
["foo", "bar"].map.|{concat("ber")}
[" foo ", "\tbar\n"].map.|{strip.upcase}
The |
character here is reminiscent of the unix pipe, which may be interpreted here as passing the values to the block, and it also resembles the ||
notation in the block. But I don't know if people might think that ugly. &
would keep resemblance to the notation using &
with symbol_to_proc
, but I don't feel the necessity to do so:
["foo", "bar"].map.&{upcase}
["foo", "bar"].map.&{concat("ber")}
[" foo ", "\tbar\n"].map.&{strip.upcase}
Even an asterisk or caret may work.
["foo", "bar"].map.*{upcase}
["foo", "bar"].map.*{concat("ber")}
[" foo ", "\tbar\n"].map.*{strip.upcase}
["foo", "bar"].map.^{upcase}
["foo", "bar"].map.^{concat("ber")}
[" foo ", "\tbar\n"].map.^{strip.upcase}
Updated by avit (Andrew Vit) almost 9 years ago
It might be confusing if such a thing only exists for Enumerator blocks and nothing else.
["foo", "bar"].map.as_self { clear }
["foo", "bar"].tap.as_self { clear } # (not an Enumerator)
What would be the correct receiver in your proposal for the following example? What happens when the method is not defined in the block's "self" object?
@members = ["foo", "bar"]
def transform_all
@members.each.as_self { transform }
end
def transform
raise "this one?"
end
A little bit related: #10095 (for the proposed syntax "as" vs. "as_self")
Updated by nobu (Nobuyoshi Nakada) over 4 years ago
Isn't it instance_eval
?