freezeできない「既存の定数」って何? - Effective Ruby

『Effective Ruby』を読んでのメモ。前回はこちら。

今日は2章の項目10まで読みすすめました。1章の続きを復習します。

項目4 定数がミュータブルなことに注意しよう

Rubyでは定数は書き換えられる値なので、書き換えられて困る値はfreezeしようという話。

配列の定数を使う場合は、配列自体と、配列の要素を両方freezeする必要がある。

疑問点

p.11の次の文章が、よく分からなかった。

定数をフリーズすれば、目立たず、追跡しにくいバグを例外に変えることができる。これは、明らかに大きなことだ。しかし、これではまだ十分ではない。定数が参照するオブジェクトをフリーズしても、既存の定数に新しい値を代入すれば、問題が起きる。

上の文章の「既存の定数」が何を意味しているのかが分からない。既存?

このくだりでは、次のようなサンプルコードで、「既存の定数」であるところのTIMEOUTという値に対して値を代入できてしまうことが示される。

irb(main):001:0> TIMEOUT=5
=> 5
irb(main):002:0> TIMEOUT += 5
(irb):2: warning: already initialized constant TIMEOUT
(irb):1: warning: previous definition of TIMEOUT was here
=> 10

ためしに定数TIMEOUT自体をfreezeするも、値を代入できてしまう。

irb(main):003:0> TIMEOUT.freeze
=> 10
irb(main):004:0> TIMEOUT += 5
(irb):4: warning: already initialized constant TIMEOUT
(irb):2: warning: previous definition of TIMEOUT was here
=> 15

定数TIMEOUTは直接freezeできない(しても意味がない?)ということは分かる。

本文では、moduleの中にTIMEOUTを定義して、module自体をfreezeするという対処法が述べられている。

項目5 実行時の警告に注意しよう

Rubyは、構文解析フェーズ(本文ではコンパイル時と呼んでいる)と実行フェーズの2つでコードを操作する。処理系のオプションを活用すると、それぞれのフェーズで別の種類の警告を表示できる。

-wオプションをつけることと、VERBOSE変数を使うことは、排他ではない。両方やれというのが筆者の主張。

警告を活用してコードを修正しよう、Rubyにコードの意図を推測させるのはやめよう、という話だった。

今日はここまで。第1章は終了。

Effective Ruby

Effective Ruby