Project

General

Profile

Feature #16166

Remove exceptional treatment of *foo when it is the sole block parameter

Added by sawa (Tsuyoshi Sawada) 10 days ago. Updated 9 days ago.

Status:
Open
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:94925]

Description

In the parameter signature of a code block for a method that is not involved in method definition or creation of lambda objects, two types of arguments ["a"] and "a" are neutralized:

instance_exec(["a"]){|foo, bar| foo} # => "a"
instance_exec("a"){|foo, bar| foo} # => "a"

instance_exec(["a"]){|*foo, **bar| foo} # => ["a"]
instance_exec("a"){|*foo, **bar| foo} # => ["a"]

This is the same behavior as with assignment constructions:

foo, bar = ["a"]; foo # => "a"
foo, bar = "a"; foo # => "a"

*foo = ["a"]; foo # => ["a"]
*foo = "a"; foo # => ["a"]

And it contrasts with constructions involved in method definition or creation of lambda objects, where the distinction is preserved:

lambda{|foo| foo}.call(["a"]) # => ["a"]
lambda{|foo| foo}.call("a") # => "a"

->(foo){foo}.call(["a"]) # => ["a"]
->(foo){foo}.call("a") # => "a"

lambda{|*foo| foo}.call(["a"]) # => [["a"]]
lambda{|*foo| foo}.call("a") # => ["a"]

->(*foo){foo}.call(["a"]) # => [["a"]]
->(*foo){foo}.call("a") # => ["a"]

However, when *foo is the sole parameter of a code block for a method that is not involved in method definition or creation of lambda objects, ["a"] and "a" are not neutralized:

instance_exec(["a"]){|*foo| foo} # => [["a"]]
instance_exec("a"){|*foo| foo} # => ["a"]

behaving in contrast to assignment constructions, and rather on a par with constructions involved in method definition or creation of lambda objects.

Particularly, existence or absence of another parameter **bar entirely changes what foo refers to:

instance_exec(["a"]){|*foo| foo} # => [["a"]]
instance_exec(["a"]){|*foo, **bar| foo} # => ["a"]

I find this behavior inconsistent and confusing. I would like to request to remove this exceptional treatment of splatted parameter *foo when it is the sole parameter in a code block. I request this behavior:

instance_exec(["a"]){|*foo| foo} # => ["a"]

History

#1

Updated by sawa (Tsuyoshi Sawada) 10 days ago

  • Description updated (diff)
#2

Updated by sawa (Tsuyoshi Sawada) 10 days ago

  • Description updated (diff)
  • Subject changed from Remove exceptional handling of *foo when it is the sole block parameter to Remove exceptional treatment of *foo when it is the sole block parameter

Updated by mame (Yusuke Endoh) 10 days ago

I agree that Ruby's arguments are insanely complex. In the basic case, "a" and ["a"] are distinguished.

p instance_exec("a")  {|foo| foo } #=> "a"
p instance_exec(["a"]){|foo| foo } #=> ["a"]

p instance_exec("a")  {|*foo| foo } #=> ["a"]
p instance_exec(["a"]){|*foo| foo } #=> [["a"]]

In some cases, they are not distinguished.

p instance_exec("a")  {|foo, bar| foo } #=> "a"
p instance_exec(["a"]){|foo, bar| foo } #=> "a"

p instance_exec(["a"]){|*foo, **bar| foo } #=> ["a"]
p instance_exec("a")  {|*foo, **bar| foo } #=> ["a"]

The rule is fairly complex or even inconsistent. I cannot understand the condition.

I have no opinion which case |*foo| should belong to. (I personally hope that |*foo, **bar| belongs to the same case as |*foo| because keywords are separated from positional arguments.)

Anyway, I don't think that it is a good idea to change the behavior just because it is inconsistent. We need an evidence that the behavior actually confuses many people, at least.

Updated by shevegen (Robert A. Heiler) 9 days ago

We need an evidence that the behavior actually confuses
many people, at least.

It does not confuse me because ... I try to avoid it altogether. :D

I think sawa's issue can be a bit shortened (sorry!) to the last
comparison:

instance_exec(["a"]){|*foo| foo} # => [["a"]]
instance_exec(["a"]){|*foo| foo} # => ["a"]

Although I may miss (or not completely understand) all of the reasoning,
I think that change would make sense (to me) - but I may not understand
the consequences.

I only remember even matz having fun in a presentation with the
whole keyword arg situation before. ;) (One reason why I try to
actually avoid keywords is because I find them more difficult to
deal/cope with than oldschool options hash. But I guess this may
differ from ruby user to ruby user since it is a personal preference.)

Perhaps there should be a simple and consistent rule for how * and **
is to be interpreted at all times, including what should happen if
both are used at the same time. What I find indeed a bit confusing
is that * changes if ** is also used. That part is very strange to
me personally. Might also be mentioned in the documentation, but
for me personally, I gladly stick to the simpler variants. :D

Updated by shevegen (Robert A. Heiler) 9 days ago

Actually that reminds me - mame mentioned that the ruby core team needs a
motivation/impetus if a change is necessary based on real usage. So I think
this may be a good call for ruby users to comment in particular when it
may affect them (either way) in actual code. Me personally I am not affected
in either way, but it may be a good idea to get a survey/query to ruby users
out there to comment, in particular when it may affect them in their own
code base or a code base they use/depend on.

Also available in: Atom PDF