Rubyの定数が、他の言語の定数とはちょっと違う意外な仕様なのは理解していたが、もうひとつ意外な仕様があることを最近知った。なんかちょっと釣りっぽいタイトルになっちゃったけど。
再代入可能な定数
Rubyの定数は、他の言語のように変更を許さない(再代入させない)定数ではないことは有名。少なくとも自分は、Rubyを始めてから結構早い段階でこの仕様について知った。そして、最初にこれを知ったとき「これって定数じゃなくね?」って思った覚えがある。
HOGE = "hoge"
HOGE = "fuga"
puts HOGE
このように再代入しても、警告は出るものの、実際の値は変わってしまう。
2: warning: already initialized constant HOGE
fuga
Rubyのこういった仕様に対して、良い意味での“ゆるふわ感”を感じる。こんなにゆるくて大丈夫?と思うくらい。
言語の硬度を測定すると、Javaは硬度8くらい、Pythonは6くらいになるのに対して、Rubyは3くらいになる。柔らかい手触りが好きだなと思う人はRubyを学ぶといいかも。 最近話題になっている人気プログラミング言語解説のRubyの項目で触れられている、この硬度の話もこういうことも含まれるんじゃないかなぁと思っている。
もうひとつの意外な仕様
意外な仕様、なんて大層なことじゃないかもだけど、今日やってみるまで知らなかった。これは逆にRubyっぽい“ゆるふわ”な感じはしない。なぜこういう仕様なのかわからない。
さて、このコードを実行したら何と出力されるでしょう?
def hoge
FUGA = "fuga"
end
puts hoge #=> 出力結果はなんでしょう?
結果は…
2: dynamic constant assignment
FUGA = "fuga"
^
なんとエラー! もしかして常識? Rubyの定数の仕様として、メソッド内では定数の定義ができない。これは意外だった。
定数の定義 (と初期化) は代入によって行われますが、メソッドの中では定義できません。
なぜこういう仕様になっているのかはわからない。けど、クラスの仕様と関連してそう。上記のエラー文でググると、同じようにハマっている人がそこそこいるのがわかる。
自分の狭いプログラミング言語経験では、こういう仕様の言語を他に見たことが無い気がする。試しに普段良く使うAS3でメソッド内に定数を定義してみたらできた。まぁ普通そうだよね。できるよね。