Rubyのライブラリを読んでいるとHashの初期化で

h = Hash.new([].freeze)
というのを良く見かける。

これはどういう意味なんだろうと調べてみた。

まずは freeze の意味 Object - Rubyリファレンスマニュアル

オブジェクトの内容の変更を禁止します。self を返します。 フリーズされたオブジェクトの変更は例外 TypeError を発生させます。
という事で、任意のオブジェクトを変更不可能にできます。

次に、Hash.new の引数の意味 Hash - Rubyリファレンスマニュアル

Hash.new([ifnone]) 空の新しいハッシュを生成します。 ifnone はキーに対応する値が存在しない時のデフォルト値です。 デフォルト値の扱いには注意が必要です。 ( trap::Hash )。

という事で、Hashオブジェクトに対して存在しないキーを要求したときに返す値をコンストラクタで指定できるらしい。
例)

h = Hash.new(4)
age = h[:age] # => 4
つまり、 Hash.new([].freeze)となっているのは、 デフォルト値を[](空配列)とし、さらにそれを 変更されては困る場合の宣言の仕方だった。 しかしこれにはtrap::Hash にもあるように、freezeを付けないと、 デフォルト値自体に破壊的な操作をすると、 混乱するから気をつけよう。と書いてあり、 その破壊的な操作の殆どは予期せず行ってしまうだろう事を 懸念している。
例)
h = Hash.new([])
# key=0の値に0を追加
h[0] << 0
# key1の値に1を追加
h[1] << 1
# 間違った期待
p h         #=> {0=>[0], 1=>[1]}
# 実際の値
p h         #=> {}
p h.default #=> [0, 1]
どうやら、freezeは上記の混乱を避ける事にも役立っている。

そういう意味だったのかぁ。。 やっと理解できました。

その他まとめ Hashオブジェクトの初期化
  1. Hash.new() キーが無い場合はnil
  2. Hash.new( obj ) キーが無い場合はobj
  3. Hash.new( ブロック ) ブロックの結果を返す ex) Hash.new( | hash, key | hash[key] = "Booo!" )
  4. 2.を使う場合は要注意 で特に値を変更するような場合は、 誤ってアクセスした時に気がつかない場合があるので、 freezeを使う。 でも個人的には、freezeを使うくらいなら、 1を採用してnilを返すようになっていれば良いと思うのだが。。 freezeにする必要があるケースを強引に考えると、 基本的に特定の範囲のキーを期待するが、 将来的に期待外のキーが与えられる可能性があり、 そのキーを拒否する事もするべきでないようなケース。。。 どんなケースだろう。