Feature #19107
openAllow trailing comma in method signature
Description
A popular style for multiline arrays, hashes or method calls, is to use trailing commas:
array = [
1,
2,
3,
]
hash = {
foo: 1,
bar: 2,
baz: 3,
}
Some.method(
1,
2,
foo: 3,
)
The main reason to do this is to avoid unnecessary noise when adding one extra element:
diff --git a/foo.rb b/foo.rb
index b2689a7e4f..ddb7dc3552 100644
--- a/foo.rb
+++ b/foo.rb
@@ -1,4 +1,5 @@
Foo.bar(
foo: 1,
- bar: 2
+ bar: 2,
+ baz: 3
)
However, this pattern doesn't work with method declarations:
def foo(bar:,) # syntax error, unexpected ')'
Proposal¶
For consistency and convenience I propose to allow trailing commas in method declarations.
Updated by byroot (Jean Boussier) almost 2 years ago
- Related to Bug #17858: Trailing comma after a `&block` parameter cause a syntax error added
Updated by shyouhei (Shyouhei Urabe) almost 2 years ago
- Related to Bug #3456: bisarre comma added
Updated by matz (Yukihiro Matsumoto) almost 2 years ago
I don't care for consistency here (since formal arguments and actual arguments are different).
I am not sure for convenience. Compare to actual arguments, there's less chance to rewrite/update formal arguments.
Is there an actual case where this proposal is convenient?
Matz.
Updated by byroot (Jean Boussier) almost 2 years ago
Is there an actual case where this proposal is convenient?
Yes, when replacing old APIs that took an "option hash" by explicit keyword arguments, it tend to create very large signature.
The last example I have in mind is redis-client
: https://github.com/redis-rb/redis-client/blob/dcfe43abb83597bee129537464e20805658bf7a9/lib/redis_client/config.rb#L21-L41
def initialize(
username: nil,
password: nil,
db: nil,
id: nil,
timeout: DEFAULT_TIMEOUT,
read_timeout: timeout,
write_timeout: timeout,
connect_timeout: timeout,
ssl: nil,
custom: {},
ssl_params: nil,
driver: nil,
protocol: 3,
client_implementation: RedisClient,
command_builder: CommandBuilder,
inherit_socket: false,
reconnect_attempts: false,
middlewares: false,
circuit_breaker: nil
)
When adding a new argument, it cause these annoying diffs:
diff --git a/lib/redis_client/config.rb b/lib/redis_client/config.rb
index fc74367..6412171 100644
--- a/lib/redis_client/config.rb
+++ b/lib/redis_client/config.rb
@@ -36,7 +36,8 @@ class RedisClient
command_builder: CommandBuilder,
inherit_socket: false,
reconnect_attempts: false,
- middlewares: false
+ middlewares: false,
+ circuit_breaker: nil
)
@username = username
@password = password
Also this inconsistency is the reason why some popular styleguides reverted back to not using trailing comma for multi-line enumerations:
Updated by rubyFeedback (robert heiler) over 1 year ago
To me the ',' there looks rather awkward. Then again the
first time I saw def(foo:) I was also confused.
Updated by k0kubun (Takashi Kokubun) over 1 year ago
I second this proposal.
def foo(bar:,)
doesn't seem like a real use-case, but when a method has so many arguments and I declare arguments in multiple lines, I would love to put a trailing comma to minimize future git diff and make reviewing the Ruby code easier.
For example, this is today's ERB#initialize
:
def initialize(str, safe_level=NOT_GIVEN, legacy_trim_mode=NOT_GIVEN, legacy_eoutvar=NOT_GIVEN, trim_mode: nil, eoutvar: '_erbout')
# ...
end
This line is still short enough to fit on my screen, however, if we were to add another option, e.g. filename
, I would write:
def initialize(
str,
safe_level=NOT_GIVEN,
legacy_trim_mode=NOT_GIVEN,
legacy_eoutvar=NOT_GIVEN,
trim_mode: nil,
eoutvar: '_erbout',
filename: nil,
)
# ...
end
which doesn't seem awkward to me. But this is a SyntaxError today. If you don't put a ,
there, you'll see a diff on filename
when you add another option after that even if the patch is not related to filename
, which would make me frustrated when reviewing that code.
here's less chance to rewrite/update formal arguments.
trim_mode:
and eoutvar:
are arguments that were added to the method afterward by updating them. attr_accessor :filename
already exists in ERB and filename:
option in #initialize
is a real feature in a competing implementation, Erubi, which has even more options that we might want to add to ERB separately, not just filename:
.