Tech Racho エンジニアの「?」を「!」に。
  • 開発

[Ruby] ブロック変数とブロック引数とProc引数の違い

こんにちは、hachi8833です。

前回の『Rubyスタイルガイドを読む: 文法(5)ブロック、proc』を書いていて、ブロック変数/ブロック引数/Proc引数の違いが気になったので調べてみました。

ブロック変数(block variable)とブロック引数(block argument)は字面が似ています。実際、ネット上でブロック変数をブロック引数と呼んでいる記事をいくつかみかけました。

ブロック引数とProc引数(Proc argument)も音が似ているのでやはり少しまぎらわしいところがあります。

結論から言うと、文献によって用語が想像以上に違っており、追った限りでは公式ドキュメントでも定めきれませんでした。用法がこんなに揺れているとは思わなかった...

はじめに: 用語について

今回調べていて、引数という言葉の難しさを痛感しました。

引数(argument)という言葉はよく使われますが、特にネット上の文章ではメソッドの「定義側」の変数やブロックなどを指すこともあれば「呼び出し側」の変数やブロックなどを指すこともあり、紛らわしさの元になります。

厳密に表す場合、冒頭でたとえば以下のいずれかのように定めてから表すなどの工夫が必要になります。後述しますが、現実にはドキュメントによって異なっています。

  • 例1: 定義側で使うものを「仮引数」、呼び出し側で使うものを「実引数」と呼ぶ
  • 例2: 定義側で使うものを「パラメータ」、呼び出し側で使うものを「引数」と呼ぶ

たとえば、Rubyリファレンスマニュアル: メソッド定義で定義側の引数を「仮引数」、呼び出し側を「実引数」と呼んでいます。

今回は記事の性質上、上の両方を使うことになりますのでご了承ください。

1. ブロック変数

  • ブロック変数という言葉は、「たのしいRuby」p102で使われています。

ブロックの最初の「| |」で囲まれた部分に指定された変数はブロック変数といい、ブロックを実行するときに、メソッドからパラメータが渡されます。
「たのしいRuby」p102より

  • しかしRubyリファレンスマニュアルのブロックでは、同じものを「ブロックパラメータ」と呼んでいます。

yield に渡された値はブロック記法において | と | の間にはさまれた 変数(ブロックパラメータ)に代入されます。
Rubyリファレンスマニュアル「ブロック」より

また、ネット上のさまざまな記事を見ると、用語ではなく、「ブロック変数」や「ブロックパラメータ」という記述的な表現になることもしばしばあります。

これらはいずれの場合も「ブロック内で| |で囲んで定義する変数」を指しています。ブロックの中を指しています。この呼び方が「ブロック変数」と「ブロックパラメータ」などと揺れているということですね。

2. ブロック引数とProc引数の違い

今回悩んだのが、このブロック引数とProc引数です。

  • ブロック引数という言葉は、bbatsocのRubyスタイルガイドのblock argumentで次のように使われています。

Consider using explicit block argument to avoid writing block literal that just passes its arguments to another block. Beware of the performance impact, though, as the block gets converted to a Proc.
[bbatsov/ruby-style-guide](https://github.com/bbatsov/ruby-style-guide/blob/master/README.md#block-argumentより

メソッド定義側でブロックを受ける、&で始まるパラメータを「ブロック引数」と呼んでいます。

  • 一方、『たのしいRuby第5版』p211では、ここでいうブロック引数に渡す引数を「Proc引数」と呼んでいます。以下は同ページのコードと引用です。
def total2(from, to, $block)
  result = 0
  from.upto(to) do |num|
    if block
    ...
  end
end

冒頭のメソッド定義の引数に&blockという引数の定義があります。このように、変数名の前に「&」をつけて受け取る引数のことをProc引数といいます。
『たのしいRuby第5版』p211より

引数定義を引き合いに出して説明しているので、定義側のブロックをProc引数と言う、と読めます。

さらに次をご覧ください。

  • 以下の書籍では、lambdaによるブロック渡しをProc argumentと呼んでいます。

Ruby Programming/Syntax/Method Callsには以下のような記述があります。

The method do_twice is defined and called with an attached block. Although the method did not explicitly ask for the block in its arguments list, the yield can call the block. This can be implemented in a more explicit way using a Proc argument:
Ruby Programmingより

def do_twice(what)
  what.call
  what.call
end

do_twice lambda {puts "Hola"} # このlambdaによるブロック渡しをProc argumentと呼んでいる

たのしいRubyの「Proc引数」はメソッド定義側を指しているようですが、Ruby Programmingではメソッド呼び出し側のlambdaによるブロック渡しを指しているようです。

最後に

当初は機能上の違いを記事にするつもりでしたが、文献ごとの用語の揺れが思ったより大きかったので、そちらを中心に据えました。

それぞれが何を指すのかは、開発者にとっては文脈でだいたいわかるので通常はそれほど問題にならないと思いますが、書籍やドキュメントではその中での一貫性が求められます。

公式に定義されていない用語はドキュメント内で「ローカルに統一するより」ないと言えばそれまでですが、こういう調べ物の場合にはなかなか大変ですね。機会を見て別記事を出したいと思います。

参考

[tmkm-amazon]B01C804DO8[/tmkm-amazon]


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。