【追記あり】Rubyの「ローカル変数のスコープにおける仕様変遷」の補助輪
2003年のスラッシュドットの記事(Matzさんのインタビュー記事)を拝読していたところ、「その後の動向」が気になる内容を見つけました。
まつもとゆきひろさん 答える
(一部抜粋)
【質問者さん】
Ruby の仕様で、これはやめておけばよかったというものはありますか?【Matzさん】
あんまりないです。今のRubyとまったく異なってRubyと同じくらい良い言語は存在できるだろうとは思いますが、Rubyをそのように変えようとは思いません。
変えるとしたら、Larryも指摘したローカル変数のスコープくらいでしょうか。 これは2.0(Rite)で変更しようと考えています。
この記事を拝読し、「ローカル変数のスコープの仕様」がその後どのように変更されていったのか(または変更されなかったのか)が気になり調べたのですが自力で見つけることができず…。
キニナル病を治すべく、Quoraで質問させていただきました😅
ささださん 答える
すると、すぐに笹田さんからご回答いただきキニナル病はあっという間に完治…!
「ローカル変数の仕様変更」として「ブロックパラメータのシャドウィング」を教えていただきました。
ありがとうございます!!
【仕様変更】ブロックパラメータのシャドウィング(Ruby 1.9 〜)
( 以下は自分なりの解釈を加えたまとめにつき、いただいたご回答の原文はぜひ上記Quoraのリンクよりご覧くださいませ🙇🏻♂️ )
# コード例 i = 10 1.times { |i| } p i
Ruby 1.8 まで
- ブロックパラメータは「外側の
i
」だった - そのため、
1.times { |i|
の部分で、ブロックの外側の変数i
に「i = 0
」と代入され、ブロックを抜けた後のp i
は「0」を出力していた
# Ruby 1.8 まで i = 10 1.times { |i| } p i #=> 0
Ruby 1.9 から
1.times { |i|
のi
が「ブロックの中のローカル変数」に変わった- (shadowing / シャドウィング)
- そのため、外側の変数とは別の変数
i
にi = 0
が代入され、ブロックから抜けても外側の変数i
はそのままなのでp i
は「10」を出力する
# Ruby 1.9 から i = 10 1.times { |i| } p i #=> 10
- ただし「外側と同じ名前を新たに使うよ」ということを明示するため、
ruby -w
で起動するとwarning: shadowing outer local variable -i
という警告を出すようにしていた- ※
ruby -w
… 冗長モードでRubyプログラムを実行する- (普段出力されないwarningを出力してくれる)
- ※
- Ruby 2.6 からこの警告は消えた
Ruby 1.9 で一緒に加わった仕様
ブロックパラメータではないが、ブロック内で同名の新しい変数を明示的に宣言するための記法(例 |; i|
)がRuby 1.9 からサポートされた。
# コード例 i = 10 1.times { |; i| i = 0 } p i #=> 10
※ 余談: この記法をどこかで見た気がして手元の書籍・自分の書きなぐりメモを探したところ、書籍「 プロを目指す人のためのRuby入門 」のP.129で紹介されていた😆
伊藤さん、さすがっス…!
(まとめ ここまで)
【2020/11/19追記】Matzさんからもご回答いただいた!
Rubyのブロックローカル変数のスコープ、実は「外側での事前の宣言(代入)を避けるアイデア」が玉造温泉で生まれていたことを教えていただきました(残念ながらその後、不採用となったようです…)。
ご興味のある方はぜひ上記QuoraのリンクよりMatzさんのご回答をご覧くださいませ🙇🏻♂️
…いや、結構上にあるのでもう一度貼っておきます!
笹田さんに続き、Matzさんからもご回答いただいてしまった…。これから自分はQuoraを「Quoraさん」と呼ぶことにします。
謝辞
笹田さん、ご回答いただきありがとうございました!
(2020/11/19追記)
Matzさん、ご回答いただきありがとうございました!