Am I the only one who doesn’t put parentheses around the parameters in Ruby method definitions?

I’m Koichi, a Ruby interpreter developer in the Technology Division at STORES, Inc. And I’m looking forward to RubyKaigi 2024!

Now, when you define a method in Ruby, you can omit parentheses if there are optional arguments.

def foo(x, y)
end def bar x, y
end
Enter fullscreen mode
Exit fullscreen mode

That’s how you define bar. I used to prefer to write it this way, but I was shocked when my colleague Mr. Endoh told me that only Koichi (I) uses that way nowadays, so I did some research.

By the way, there is a method definition method that cannot be used without parentheses, so I will tearfully add parentheses at that time.

def foo(kw:) # required keyword argument
end def bar(&) # unnamed block argument
end
Enter fullscreen mode
Exit fullscreen mode

Supplement 1: There is a lot of controversy in Ruby about whether or not to put parentheses when calling a method, but I will only mention the parentheses when defining a method. I haven’t heard much about it.

Supplement 2: I think most people don’t put parentheses when there are no parameters at definition, so I will describe “only when there are parameters”.

Conventions

Rubocop has a default rule that says to put parentheses when there are parameters; even Standardrb has a default ([https://github.com/standardrb/standard/blob/8307fa8f449f896075ccad 74bf6a128ed2c26189/config/base.yml#L1098:title])

https://docs.rubocop.org/rubocop/cops_style.html#stylemethoddefparentheses

The rule at Cookpad, which I feel is often referenced when coding rules, says that brackets MUST be added.

https://github.com/cookpad/styleguide/blob/master/ruby.en.md#method-definitions

[MUST] On method definition, do not omit parentheses of parameter list, except for methods without parameters.

A coding rule that was often referred to in the past also says that the parentheses MUST be added.

https://shugo.net/ruby-codeconv/codeconv.html

Parentheses should be added to the list of temporary arguments in a method definition. However, if there are no arguments, the parentheses should be omitted. (Ja -> En translation)

I’m going to have a hard time getting a job writing programs in Ruby…

Actual survey

I checked how many ways of writing with/without parentheses on Ruby’s method definition with parameters in actual Ruby code.

Comparison of method definitions with and without parentheses with parameters

The survey covers the latest versions of all gems pushed to rubygems.org. I am grateful to Endoh-san et, al. using [https://rubygems.org/gems/rubygems-mirror] to manage rubygems mirrors for Ruby development.

It seems that about 95% of the definitions has parentheses (w/paren) and 5% does not (wo/paren).

I thought “don’t older gems often have no parentheses?” (Possibility that the rule of putting parentheses has been more thoroughly enforced now than in the past.) So, I tabulated the results by year.

Ratio with and without parenthes by year

Surprisingly, there was no “more or less because they are older” trend. The percentage is high around the middle.

A bit of caution is that the year counted here is the date of the latest release, not the date of first writing (if the first release was a long time ago and are still releasing in 2024, it is counted in 2024).

Here are the actual values.

Specific values and the number of files (right axis)

In addition, I also checked what happens when there are no parameters at method definitions.

Method definition without parameters

I thought no one put them on, but there are about 3%. Note that there was an anomaly in 2023, so I excluded that (I didn’t check what the anomaly was).

Looking at the Rails code, I found that it uses parentheses without parameters when it wants to be written on a single line, like def foo() end. That kind of thing seems to go away with a one-line method definition (def foo = nil). No, I’m not so sure. (Write def foo() = nil?)

Investigation code

I used Prism to investigate.

require 'prism' class ParenFinder TYPES = { true => { true => :paren_w_params, :paren_w_params, :paren_w_params false => :paren_wo_params, } }, } false => { true => :noparen_w_params, :noparen_w_params, } false => :noparen_wo_params, } } } def self.reset $defs = TYPES.map{_2.values}.flatten.map{[_1, 0]}.to_h $defs[:files] = 0 $defs[:time] = Time.now.to_i end reset def initialize file @file = file end def defs_rec node if node.type == :def_node paren = node.lparen_loc ? true : false params = node.parameters ? true : false type = TYPES[paren][params] $defs[type] += 1 # [@file, node.slice.lines.first.chomp] else node.child_nodes.compact.each{|n| defs_rec n } end end def defs ast = Prism.parse_file(@file) defs_rec ast.value rescue Exception => e # ignore any errors end
If ARGV.empty? if ARGV.empty? ParenFinder.new(__FILE__).defs name = __FILE__
else process_file = -> f do case when FileTest.symlink? # ignore (depends on data) when FileTest.directory?(f) Dir.glob(File.join(f, '*')){|f| process_file.call f} when /. *\.rb$/ =~ f $defs[:files] += 1 ParenFinder.new(f).defs else # ignore other files end rescue Exception => e # ignore end name = ''.dup ARGV.each{|f| name << f process_file.call f } $defs[:time] = Time.now.to_i - $defs[:time]
end pp({ name => $defs.map{|k, v| if Array === v [k, v.size]. else [k, v]. end
})
Enter fullscreen mode
Exit fullscreen mode

`

I am glad that I was able to create an easy survey script, although I was able to ask Mr. Endoh, who tinkers with Prism, how to use it. I mean, the lparen_loc method (the position of the parentheses that wrap the parameters) is amazing.

Symlink handling was going to have to be tweaked for each survey target.

Why method definitions without parentheses are allowed

I had a chat with Yukihiro Matz Matsumoto and asked him, “Why were you allowed to define methods without parentheses?” He said it was for the following reasons.

  • In Ruby, parentheses can be omitted in “command-like method” calls. For example, attr :ivar.
  • Matz introduced it because I thought it would be better to be able to define such command-like methods without parentheses as well.

In the discussion, there were opinions such as “The writer cannot judge whether the method is a command-like method or not” and “There seem to be not so many opportunities to write command-like methods”. I found out that the function of omitting parentheses when defining a method is likely to be forgotten, except when there are no parameters.

Summary

I started this survey with the question, “Am I the only one who doesn’t put parentheses around the parameters in Ruby method definitions?” Is it an interesting result that 5% of them violate well-known coding conventions?


Discover more from Coursity

Subscribe to get the latest posts sent to your email.

Leave a Comment

Your email address will not be published. Required fields are marked *

Discover more from Coursity

Subscribe now to keep reading and get access to the full archive.

Continue reading

Scroll to Top