## Feature #15897

### it as a default block parameter

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

Description

How about considering "it" as a keyword for the block parameter only if it is the form of a local varaible reference and if there is no variable named "it"?

[1, 2, 3].map { it.to_s } #=> ["1", "2", "3"]


If you are familiar with Ruby's parser, this explanation is more useful: NODE_VCALL to "it" is considered as a keyword.

Examples:

public def it(x = "X")
x
end

[1, 2, 3].map { it.to_s }    #=> ["1", "2", "3"]
[1, 2, 3].map { self.it }    #=> ["X", "X", "X"] # a method call because of a receiver
[1, 2, 3].map { it() }       #=> ["X", "X", "X"] # a method call because of parentheses
[1, 2, 3].map { it "Y" }     #=> ["Y", "Y", "Y"] # a method call because of an argument
[1, 2, 3].map { it="Y"; it } #=> ["Y", "Y", "Y"] # there is a variable named "it" in this scope

it = "Z"
[1, 2, 3].map { it.to_s }    #=> ["Z", "Z", "Z"] # there is a variable named "it" in this scope


Pros:

• it is the best word for the feature (according to matsuda (Akira Matsuda))
• it is reasonably compatible; RSpec won't break because their "it" requires an argument

Cons:

• it actually brings incompatibility in some cases
• it is somewhat fragile; "it" may refer a wrong variable
• it makes the language semantics dirty

Fortunately, it is easy to fix the incompatible programs: just replace it with it(). (Off topic: it is similar to super().)
Just inserting an assignment to a variable "it" may affect another code. This is a bad news, but, IMO, a variable named "it" is not so often used. If this proposal is accepted, I guess people will gradually avoid the variable name "it" (like "p").
The dirtiness is the most serious problem for me. Thus, I don't like my own proposal so much, honestly. But it would be much better than Perlish @1. (Note: I don't propose the removal of @1 in this ticket. It is another topic.) In any way, I'd like to hear your opinions.

An experimental patch is attached. The idea is inspired by jeremyevans0 (Jeremy Evans)'s proposal of @.

P.S. It would be easy to use _ instead of it. I'm unsure which is preferable.

Files

Related issues

 Related to Ruby master - Misc #15723: Reconsider numbered parameters Feedback Actions

### History

#### Updated by mame (Yusuke Endoh)6 months ago

• Related to Misc #15723: Reconsider numbered parameters added

#### Updated by Hanmac (Hans Mackowiak)6 months ago

_ can't be used as default block parameter because it already has a special meaning when using block variables like {|a,_,_,b| }

#### Updated by mame (Yusuke Endoh)6 months ago

You cannot use both it and the ordinal parameter |a,_,b| simultaneously. It will cause a SyntaxError like this.

#### Updated by Benoit_Tigeot (Benoit Tigeot)5 months ago

Eregon (Benoit Daloze) wrote:

What do you think about _?

I'm unsure if it's confusing in practice, they are used in fairly different contexts, and it is never used alone (no args, no block) by RSpec AFAIK.

I think Jon express my feelings with a clear example.

For _ same thing. It is already use and it can lead to an issue: https://bugs.ruby-lang.org/issues/15897#note-3

#### Updated by Eregon (Benoit Daloze)5 months ago

JonRowe (Jon Rowe) wrote:

it # creates a pending example with no implementation

Is that used in practice though? I know pending examples, but I would expect they at least have a description.

FWIW, MSpec's it requires the description argument, so it cannot ever be ambiguous for the user.
https://github.com/ruby/mspec/blob/ca2bc422cd8f8ddb23629e972372cf8e49f992fc/lib/mspec/runner/object.rb#L14

Benoit_Tigeot (Benoit Tigeot) wrote:

For _ same thing. It is already use and it can lead to an issue: https://bugs.ruby-lang.org/issues/15897#note-3

I think that comment is unclear.
It just means named and unnamed arguments are incompatible, just like currently in trunk, foo { |named_arg| @1 } is a SyntaxError.
foo { |_| _ * 3 } and foo { _ * 3 } would both work fine.

#### Updated by JonRowe (Jon Rowe)5 months ago

Is that used in practice though? I know pending examples, but I would expect they at least have a description.

No but as Ruby doesn't allow method overloading you do create that ambiguity, and the possibility for future bugs due to precedence rules.

FWIW, MSpec's it requires the description argument, so it cannot ever be ambiguous for the user.

Yes it can, as you are creating method / variable shadowing in built to the language, so its always ambiguous, is this the method or the variable.

#### Updated by Eregon (Benoit Daloze)5 months ago

JonRowe (Jon Rowe) wrote:

FWIW, MSpec's it requires the description argument, so it cannot ever be ambiguous for the user.

Yes it can, as you are creating method / variable shadowing in built to the language, so its always ambiguous, is this the method or the variable.

I think this ambiguity is fairly intuitive and easy to resolve:
it's exactly the same rule as for method calls without arguments, if we consider it is always defined as a local variable.
I.e., if there are no arguments, it's always the variable/default block parameter, otherwise it's a method call with the given arguments.

I think it's going to be extremely rare for it to be confusing in practice, once people know about the default block parameter feature.

#### Updated by joallard (Jonathan Allard)5 months ago

Eregon (Benoit Daloze) wrote:

I think this ambiguity is fairly intuitive and easy to resolve:

[...] if there are no arguments, it's always the variable/default block parameter, otherwise it's a method call with the given arguments.

I think it's going to be extremely rare for it to be confusing in practice, once people know about the default block parameter feature.

I would echo Benoit's comments here. As an avid RSpec user, I employ it "does something" without a block fairly often for prototyping. However, I virtually never use a completely naked it, no arguments or block, which seems to be the issue here. Even then, if I really need a naked 'it', I could always write it().

The following, taken from Jon Rowe's example above, makes total sense to me:

RSpec.describe do
it "will do the thing" do
it # without arguments, we're referring to a thing whose meaning is given by the context
end

it    # meaning given by context: first block argument

it()  # empty, description-less example (not affected)
it{}  # also unaffected
end


While I do empathize with our RSpec folks, I don't see the value in preventing an expressive keyword to exist (which would be useful in a lot of cases) in order to save the ability to use the empty it, which has a pretty limited use. Especially considering if one really needs the latter, they may just write it(), a simple workaround.

The value of an expressive, language-based keyword is something I value and makes sense to me in Ruby's design based on natural language.

With that said, I'd support finding an alternative keyword, but it seems that based on previous discussions, we've not been able to find one that makes better consensus. I haven't either. Besides, we could make similar criticisms about those other keywords (item, this/that, one/other, ...)

#### Updated by JonRowe (Jon Rowe)5 months ago

Its worth pointing out that this would always have to be lower priority than methods and other such locals defined in order to allow code to work. If precedence for this was changed to later override existing definitions of it, or simply ban them as is the case with other ruby keywords, it would break RSpec and Mspec. Consider:

it = 'is my string'
something do
it # what whould this be? the argument to the block or the string?
end


From my experience maintaining RSpec I think newcomers would either never know about it, or struggle to realise what is going on.

All just my opinions of course :)

#### Updated by mame (Yusuke Endoh)5 months ago

JonRowe (Jon Rowe) Thank you for your opinion, but I'd be happy if you could read my original proposal carefully. I've already pointed out the issue (and said my opinion against the issue).

Cons:

• it is somewhat fragile; "it" may refer a wrong variable

Just inserting an assignment to a variable "it" may affect another code. This is a bad news, but, IMO, a variable named "it" is not so often used. If this proposal is accepted, I guess people will gradually avoid the variable name "it" (like "p").

I hear from some people that they are actually using a variable it. That's unfortunate, but I still think that a soft keyword "it" is the best solution, as long as we need to add a something like @1 (and matz strongly wants to add something).

#### Updated by JonRowe (Jon Rowe)5 months ago

mame (Yusuke Endoh) I did, I apologise for not making it clear, I'm reiterating it to add weight to the con, its not just a simple "it is somewhat fragile, it may refer to a wrong variable" its a "this shadows the most commonly used method in the most downloaded rubygem"1, its not one or two people this will affect.

I welcome the feature, I just think the name is wrong, something special like _1 etc would be better.

#### Updated by Eregon (Benoit Daloze)5 months ago

JonRowe (Jon Rowe) wrote:

its a "this shadows the most commonly used method in the most downloaded rubygem"[1], its not one or two people this will affect.

It only "shadows" (by that I understand "no longer works in that case") for the case of it without any description, block and parenthesis, right?
Which seems extremely rare as said before.
So I expect only people using a plain it from RSpec would be affected, and I would expect very few people use that (it doesn't even seem tested in RSpec's test suite).

If using a local variable named it, it continues just referring to that local variable in that method.

If precedence for this was changed to later override existing definitions of it

I believe it will never change if introduced, breaking RSpec is not an option.

#### Updated by Eregon (Benoit Daloze)5 months ago

I think we should listen to RSpec users here like joallard (Jonathan Allard) and would welcome more users to reply on this thread.
People who maintain software defining it probably have a different view than their users.
If RSpec users understand it well, then I think that addresses the "potential confusion" point for RSpec.

#### Updated by ivoanjo (Ivo Anjo)5 months ago

As a user of both Kotlin and RSpec, here's my 0.01 cents: I've been using Kotlin for almost 1.5 years, and the implicit it is really nice shortcut, without making the code too harder to understand. Even newcomers seem to get it pretty quickly. I'd definitely use it if I had it in Ruby (and I do miss it when I switch between Ruby and Kotlin).

On the other hand the coincidence with RSpec's it DSL is rather unfortunate. Would be better if this could be made a keyword, but that's clearly not an option, neither for it nor for other options on this thread.

Would it be reasonable to perhaps emit a warning when it is used naked in a scope where it is defined as a method that can be called with zero args? That way we could slowly push away any remaining confusing issues, and perhaps the RSpec maintainers may consider dropping zero args it in a future 4.x release?

#### Updated by shevegen (Robert A. Heiler)5 months ago

Just a very brief comment since it was discussed in the last developer meeting, solely on the
syntax issue of %1, %2, versus @1, @2 and :1, :2:

To me personally, %1, %2 is almost the same as @1, @2. I'd still prefer @1 @2 etc... but I
don't have a huge problem with %1, although I find @1 more elegant than %1, purely syntax-wise.

The idea for :1, :2 on the other hand, though, looks somewhat strange to me.

It reminds me more of a symbol than @1 reminds me of an instance variable, oddly enough.

If @1 would not be considered to be good from a syntax point (although I find it just
fine), then I think %1 would be better than :1.

To those who would like to have a look at the developer meeting log, the summary was
provided by mame (I think) here: