先週、届いたRuby Weeklyに面白そうなトピックが紹介されていました。
Ruby 3.4 Will Have 'it'
— There’s never been any doubt: Ruby has it. But now as well as the ‘it’ factor,
it really will have it. Confused? it is a nicer looking shortcut to the first parameter in a block (a la _1) – e.g. arr.each { puts it }.
Ruby 3.3 will warn on it with 3.4 (due in a year’s time) getting the real deal.
TAKASHI KOKUBUN
Re-reconsider numbered parameters: it
as a default block parameter
ふむふむ...。
要するにRuby3.4系では、ブロック構文のデフォルトパラメーターにit
が設定されてブロック引数をしてしなくても要素の参照が可能になるということです。
# 3.4系だとOK [1,2,3].each do puts it end
なぜ追加されるのか
正直な所、ブロック引数のデフォルトパラメーターが設定されることの何が嬉しいのか個人的にはよく分かりませんでした。ブロック引数を指定すれば良いだけの話です。
Ruby Weeklyを見た時点では新機能についてのトピックなのかと思いましたが、Ruby Masterを見た所、既存機能の改善に関する提案でした。
実はすでにブロック構文でブロック引数を省略しても、_1, _2...
(Numbered parameters)のように値を参照することができるようです。自分はこの機能について全く知りませんでした。
[1,2,3].each do puts _1 # 1 2 3 end
ただNumbered parametersを積極的に使いたいのかというと微妙ですね。
Ruby Masterでも議論されていましたが、_
が変数名に付与されていると未使用変数のように感じられますし、ナンバリングされていることによってブロック引数の順序を理解している必要があります。その時点で自分ならブロック引数を明示的に宣言したいです。
ブロック構文が多くの場合、1つのブロック引数を取るためデフォルトパラメーター(_1
)が便利なのは分かりますが、見た目が良くないのでit
があったほうが良いという意見は確かに...と感じました。
個人的には_1
よりはit
の方が視認性が良いと感じました。
バージョンによる動作の違い
Ruby Masterには3.3系ではit
をデフォルトパラメーターとして使用すると警告が表示されて、3.4系ではブロック内部でデフォルトパラメーターit
の参照が可能になると記載がありました。まだ3.4系は公開されていないので動作を確認することはできませんが、3.3系は試すことができました。
Ruby: 3.3.0-dev
Ruby Masterの記載通り、警告が表示されました。
ただしit
が参照できないためにエラーになりました。
[1,2,3].each do puts it end (none):6: warning: `it` calls without arguments will refer to the first block param in Ruby 3.4; use it() or self.it it-verification.rb:6:in `block in <main>': undefined local variable or method `it' for main (NameError) puts it ^^ from it-verification.rb:5:in `each' from it-verification.rb:5:in `<main>'
ブロック引数にit
を指定した場合にも警告が出力されるのかと思いましたが、思い違いでした。
Rubyはレキシカルスコープなので、ブロック引数にit
が指定されていればデフォルトパラメーターのit
を上書きしているのでしょうか。それならば警告が出力されないのも納得です。
[1,2,3].each do |it| puts it end # 1, 2, 3
Ruby: 3.2.2
警告が表示されず、単にエラーになりました。
it-verification.rb:6:in `block in <main>': undefined local variable or method `it' for main:Object (NameError) puts it ^^ from it-verification.rb:5:in `each' from it-verification.rb:5:in `<main>'
もちろん、ブロック引数をきちんと宣言すればエラーになりませんでした。
[1,2,3].each do |it| puts it # 1 2 3 end
似たような機能を持つ言語はあるのか
it
のようにデフォルトパラメーター(暗黙的な引数)を受け取る言語がいくつかあるようです。
自分が調べた限りだと、Ruby Masterでも紹介されていたKotlin。他にはGroovyとSwiftに同じような機能が実装されているようでした。
fun main() { val numbers = listOf(1, 2, 3, 4, 5) numbers.forEach { println(it) } }
def numbers = [1, 2, 3, 4, 5] numbers.each { println it }
let numbers = [1, 2, 3, 4, 5] numbers.forEach { print($0) }
JVM上で動作するKotlinとGroovyはit
。Swiftは$0
が参照可能でした。
Swiftは現在のRubyのNumbered parametersと非常によく似たデフォルトパラメーターを提供していました。
やはりit
の方が視認性が良いですね。引数を2つ以上取る場合であれば、明示的に引数を宣言すれば良いですし、そういったケースでit
のようなデフォルトパラメーターを使うという方針が個人的には違和感があります。
Ruby3.4でit
が使えるのが楽しみです。
少しでも「ええな〜」と思ったらはてなスター・はてなブックマーク・シェアを頂けると励みになります。