Feature #6869

Do not treat `_` parameter exceptionally

Added by Alexey Muranov over 1 year ago. Updated 11 days ago.

[ruby-core:47195]
Status:Open
Priority:Normal
Assignee:Yukihiro Matsumoto
Category:core
Target version:Next Major

Description

I started by commenting on #6693, but i have realized that this is a slightly different request.

I propose to not treat the variable name "_" exceptionally. Current behavior:

 {0=>1}.each_with_index { |_,_| p _ } # [0, 1]

prints "[0, 1]", but

 {1=>2}.each_with_index { |x,x| p x } # SyntaxError: (eval):2: duplicated argument name

raises "SyntaxError: (eval):2: duplicated argument name".

Similarly for methods:

 def f(_, _)
   _
 end
 f(0, 1) # => 0

 def f(x, x)
   x
 end # => SyntaxError: (eval):2: duplicated argument name

Observe also that the use of repeated _ parameter is not consistent between methods and blocks: for methods the value is the first assigned value, and for blocks it is the array of all the assigned values.

  1. I propose to use the same rule for all variables, without distinguishing _ specially.

In particular i propose to allow to repeat any variable, not only _, in block or method arguments without raising an error.

There may be several solutions what the repeated argument will hold: it may hold the array of all assigned values, the first assigned value, the last assigned value, the first non-nil assigned value, or the last non-nil assigned value.

  1. I propose to treat repeated arguments in methods and in blocks the same way (do not know which one).

  2. For unused variables i propose to introduce a special placeholder, for example "-" not followed by anything other than a delimiter (comma or bracket):

 each_with_index { |-, value| puts value }

 -, -, suffix = parse(name)

History

#1 Updated by Eric Hodel over 1 year ago

  • Category set to core
  • Assignee set to Yukihiro Matsumoto

Seems to be part of variable shadowing checks. The check was added before r8857 (which was a refactor of the feature) and checking for '_' was removed in r14186.

Since it was committed by matz I think your chances at acceptance are low.

#2 Updated by Marc-Andre Lafortune over 1 year ago

Hi,

alexeymuranov (Alexey Muranov) wrote:

I propose to not treat the variable name "(({_}))" exceptionally.

Sorry for the naive question, but why? What are you trying to achieve? What real world problem do you want to fix?

  1. For unused variables i propose to introduce a special placeholder

I feel that unused variables do not warrant a change to the already complex Ruby syntax.

#3 Updated by Alexey Muranov over 1 year ago

marcandre (Marc-Andre Lafortune) wrote:

Hi,

alexeymuranov (Alexey Muranov) wrote:

I propose to not treat the variable name "(({_}))" exceptionally.

Sorry for the naive question, but why? What are you trying to achieve? What real world problem do you want to fix?

I do not like exceptions. When i was first learning Ruby, i thought that the underscore is a letter like any other, but sometimes it behaves like any other, and sometimes not.

It also seems to me more natural to use a placeholder for a discarded value than to assign it to a variable first and then discard.

  1. For unused variables i propose to introduce a special placeholder

I feel that unused variables do not warrant a change to the already complex Ruby syntax.

In my opinion, treating variables differently based on their names is also a part of syntax, and in my opinion such rules are harder to follow than a rule for a single placeholder. As there is no dedicated placeholder in Ruby now, this one may be adapted later to other situations as well, i think.

Update: The most important real world problem this addresses is reading the code! With a placeholder, it is immediately clear that the value is discarded, but with a special variable one needs to look through the code to be sure it is not used somewhere.

Plus one needs to remember currently what a repeated variable is holding in different situations.

#4 Updated by Alexey Muranov 12 days ago

It looks like the use of the underscore _ as a "placeholder" is quite common in other languages ("black hole" register in Vim, "whatever" pattern that matches everything in Haskell), but there it is really a placeholder and not a variable: values "assigned" to _ cannot be retrieved.

With this in view, maybe, instead of this my proposal, the underscore can be "downgraded" to a "placeholder" (or "black hole" peudo-variable)?

#5 Updated by Nobuyoshi Nakada 11 days ago

  • Description updated (diff)

Alexey Muranov wrote:

Observe also that the use of repeated _ parameter is not consistent between methods and blocks: for methods the value is the first assigned value, and for blocks it is the array of all the assigned values.

It is unrelated to _, but because of Enumerable#each_with_index.
Try:

{0=>1}.each_with_index {|x,y| p x} # [0, 1]

Alexey Muranov wrote:

It looks like the use of the underscore _ as a "placeholder" is quite common in other languages ("black hole" register in Vim, "whatever" pattern that matches everything in Haskell), but there it is really a placeholder and not a variable: values "assigned" to _ cannot be retrieved.

Isn't it more exceptional?

#6 Updated by Alexey Muranov 11 days ago

Nobuyoshi Nakada wrote:

Alexey Muranov wrote:

Observe also that the use of repeated _ parameter is not consistent between methods and blocks: for methods the value is the first assigned value, and for blocks it is the array of all the assigned values.

It is unrelated to _, but because of Enumerable#each_with_index.
Try:

{0=>1}.each_with_index {|x,y| p x} # [0, 1]

Thanks, i do not know what i was thinking.

Alexey Muranov wrote:

It looks like the use of the underscore _ as a "placeholder" is quite common in other languages ("black hole" register in Vim, "whatever" pattern that matches everything in Haskell), but there it is really a placeholder and not a variable: values "assigned" to _ cannot be retrieved.

Isn't it more exceptional?

Yes, so this proposal would need to be closed, and i would need to open a new one. When i opened this one, i did not know that the underscore was a common "placeholder" in other languages and i thought that Ruby documentation presents the underscore in identifiers roughly as equivalent to a lowercase letter (doesn't it?).

Here is a sentence from the online version of Programming Ruby:

In these descriptions, lowercase letter means the characters ''a'' though ''z'', as well as ''_'', the underscore.

In any case, in Ruby the following works perfectly, and in my opinion this all is confusing:

_ = 1
p _

So, yes, my new proposal would be to downgrade the underscore to a placeholder, so that in something like this

foo do |_,x|
  # 10 lines of code
end

or

_, _, suffix = parse something

it would be immediately clear the values "assigned" to _ are discarded.

Also available in: Atom PDF