SEAN_BLOG

プログラミング etc.

Ruby 2.7 の新機能(Numbered parameters 編) - チケットとコミットログを読んでみて

5月30日(木)、Ruby 2.7.0 preview1 がリリースされましたね。

パチパチパチ👏🎉👏

さて、前回のパターンマッチング編に引き続きRuby 2.7 の新機能、Numbered parameters についてまとめていきます。

Numbered Parameters

TL;DR

  • ブロックパラメターに @1, @2 という新しい記法を用いることが可能。
  • @n の記法はインスタンス変数を想起させ見慣れないが、時が解決してくれる(きっと)。
  • Hash でNumbered parameters を用いると著しく可読性が下がる(気がする)。

使用例

#w/o Numbered parameters
[1, 2, 3].map { |n| n + 2 }

#w/ Numbered parameters
[1, 2, 3].map { @1 + 2 }

#w/o Numbered parameters
{ key1: 'foo', key2: 'bar' }.map { |key, val| [key, val] }

#w/ Numbered parameters
{ key1: 'foo', key2: 'bar' }.map { [@1, @2] }

今まではこんな感じでブロックパラメターに名前をつける必要がありました。 しかし、Ruby 2.7 では @ を用いたデフォルト値を使うことができます。 便利そうですが、Ruby@ というとインスタンス変数を想起してしまいます。。。

チケット

今回もチケットの内容を読み解いてみることにします。

bugs.ruby-lang.org

@my_sons.each { |s| s.sell_to_someone }

Account.all.each { |a| my_account << a.money }

そもそもNumbered parameters という概念の始まりは、

ブロック中の変数の名前、そこまで重要でない時もありますよね。 もしかして、デフォルト値作ったら便利じゃないですか?

というところのようです。 ちなみに、チケットでは下記のようなサンプルコードも挙げられています。

Account.all.each { my_account << it.money }

お、it が。。。 これはRSpec の方々が黙ってなさそう。 と思ったらやはり、RSpec 等の既存のコードとの互換性の問題で it は却下されていました。

現状trunk にマージされたNumbered parameters は @n という形を取っています。

Matzさん曰く、「@ の見た目は、最初慣れないけどそのうち見慣れるでしょ!」とのことです。

I still feel weird when I see @ and @1 etc. Maybe I will get used to it after a while. I need time.

議論の中では先ほど挙げた it 、そして意味的にそれに近い this。 記号系では、\n$n&n. なんかも候補に挙げられてました。 あと、`(backtick)? この辺の記号を地上げして使えば良いみたいな少し過激な意見もありました。

そしてこのNumbered parameters ですが、非常に議論が盛り上がっているようで、 trunk にマージされた後も新規でチケットが起票されていました。

bugs.ruby-lang.org

その他個人的に印象に残った意見が、数文字のタイプを減らすために、ここまで可読性を犠牲にするのはどうかと言ったものです。 さらには、可読性が落ちることで初学者の学習コストが上がると言ったところ言及されており、 機能追加の段階でここまでの議論がなされているものなのかと驚きました。

また、Numbered parameters を利用した実例として、ネガティブな反応が多かったのがHash を用いたケース。

h = Hash.new { |hash, key| hash[key] = "Go Fish: #{key}" }

#vs

h = Hash.new { @1[@2] = "Go Fish: #{@2}" }

確かにこれは、Numbered parameters を使うとわかりづらいかも。。。

これを受けて、Matzさん

So use numbered parameters with care (just like other features in Ruby)

「(他の機能もそうだけど、)注意して使いましょうね。」とのこと。

時と場合によりけりといったところでしょうか。

コミットログ

github.com

さて、お待ちかねのコミットログです。 今回も前回同様、テストコード中心に読み進めていきます。

まずこちら、

assert_syntax_error('proc {|| @1}', /ordinary parameter is defined/)
assert_syntax_error('proc {|x| @1}', /ordinary parameter is defined/)

|x| といった現状のブロック変数との併用はできないようです。

assert_syntax_error('proc {@1 = nil}', /Can't assign to numbered parameter @1/)

ブロック中でNumbered parameter に値をアサインすることも出来ないようです。

assert_syntax_error('proc {@01}', /leading zero/)
assert_syntax_error('proc {@1_}', /unexpected/)

0 から始めるのもエラーのようですね。

アンダースコア用いることも出来ないようです。 と言っても、あんまり利用例も考えつきませんが。。。

assert_syntax_error('proc {@9999999999999999}', /too large/)

これは。。。too largeです。。。笑

assert_syntax_error('@1', /outside block/)

もちろん、ブロックの外でNumbered parameter を呼ぶのもエラーが出ます。

所感

RubyKaigi 2019 期間中初めて、Numbered parameters の存在を知ったのですが、その時は便利そうだなーと思いました。 ただ、今回チケット・コミットログを読んでみて、Hash のケース等は可読性が著しく下がってしまい、一概に便利ということではないようですね。 Matzさんもおっしゃる通り、節度を持って利用したいと思います。

Ruby 2.7 では Enumerable#filter_map というメソッドが新しく導入されています。 この辺とNumbered parameters 一緒に使ってみたいですね。 気が向いたら、Enumerable#filter_map についても記事まとめます!

では、今回はこの辺で。

最後まで読んで頂きありがとうございます🙇

参考