ころんころん
::
をどう発音するか自分は寡聞にして知らないのだが、筆者は心のなかでころんころんと呼んでいる。
ちょっとかわいい音感だ。
そんなころんころん
に関して、ふだん意識せずに使っている人もいるだろうから、短いながらもころんころん
について解説したい。
ころんころんとは何者か
::
である。
ここで言うところの::
はruby
の演算子の中で最も優先度の高いスコープ演算子であるころんころん
だ。
ruby
では演算子の組み合わせである自己代入演算子は再定義できない。
先刻ご承知の通り再定義に関してはおおらかなruby
ではあるが、ころんころん
もころん
ところん
な自己代入演算子であるからにして、これもまったき再定義できない1。
つまるところころんころん
はruby
という言語に組み込まれた制御構造である。
ころんころんはどう使うのか
::
を使うに、あまり卓越していない小輩の身ではあるのだけれど、一例の一つや二つ、二例三例と紹介するには吝かではない。
::
はスコープ演算子であるのだが、これは名前空間を表すために利用される。
ruby
ではモジュールもクラスも定義するとその名前を定数として持ったオブジェクトになる。ちなみにClass
クラスはModule
クラスのサブクラスである。
$ Module.class
#=> Class
$ mod = Module.new #無名の module を作成
$ mod.class
#=> Module
モジュールを定義したとき、モジュール名と同じ定数にモジュールオブジェクトが代入される。これはクラスを定義した場合も同じである。
まあ上記の例では無名のモジュールクラスを作成しているので名前となるべき定数がない。無名の場合は最初に代入された定数がその名前になる。以下はその用例だが、筆者はこのコードの実際の使用例を見たことがない。
$ mod.name
#=> nil
$ hoge = mod
$ hoge.name
#=> nil
$ Hoge = mod
#=> Hoge
$ mod.name
#=> "Hoge"
話が逸れた。
とにかく::
は、このモジュールやクラス内で定義された定数名を外部から参照するときに使用されるのだ。
module Foo
module Bar; end
end
階層構造を持ったモジュールを参照してみよう。
$ Foo
#=> Foo
$ Bar
# => NameError: uninitialized constant Bar
$ Foo::Bar
#=> Foo::Bar
ついに::
の用例が出てきたぞ!
Foo
の中で宣言されたBar
はそのままでは参照できない。参照するためには正しくFoo::Bar
とその階層構造通りに場所を示す必要がある。
では以下のように宣言すればどうなるであろうか。
module Moge
module ::Piyo; end
end
おそらく読者諸兄は上掲の用例を見かけたことが有るであろう。::
は左辺が省略できるのである。
$ Moge
#=> Moge
$ Piyo
# => Piyo
$ Moge::Piyo
#=> NameError: uninitialized constant Moge::Piyo
先ほどと、結果が変わった。Piyo
はMoge
の下で宣言したように見えて、Moge
の配下にはいないのだ。そしてどうやらPiyo
とMoge
は同じ階層にいるようなのだ。
それでは::
の省略された左辺とはなんであろうか、また、::
を書かずともモジュールを宣言した場合にいったいどこの配下にいるのか。上掲の無名モジュールの用例に続けて、モジュールの定義された場所を参照するためにそのスーパークラスを確認してみよう。
$ mod.class.superclass
#=> Object
Object
クラス!
そう、Object
クラスに定義されるのだ。ころんころん
はたんにころんころん
ではなく、オブジェクトころんころん
だったのだ。
ここに定義されている定数をトップレベルの定数と呼び、そしてこの場所こそが::
がスコープ演算子として使用された場合の省略された左辺なのである。
オブジェクトころんころんの名前空間の使い方
前項で::
の省略された左辺で示す場所とはObject
クラスの配下であると示した。
また、無名モジュールを宣言した際にObject
クラスに定義されていることも示した。
ところで先日、筆者は異なる場所でトップレベルの配下に宣言されたモジュールで、複数形と名詞系が同じ語の名前空間が衝突したために、それを解決すべく新しく名前空間を切った。
そしてそれを解決する過程で多くのオブジェクトころんころん
を目にした。もちろん筆者が過去に書いたものもある。本当は、今いる場所をきちんと考えれば不要なはずなのにだ。申し訳ない。
オブジェクトころんころんはなるべくやめよう
Object
クラスの名前空間はすぐに使いやすい定数を入れてしまうので、名前が衝突しやすい。
いつどんな予期せぬ参照が起きるかわからない繊細なものである。
正しく名前空間を切って、どこにも所属しないオブジェクトころんころん
な定数の宣言を減らし、有限な資源を効率良く使うようにしていくことが肝要なのである2。そういったころんころん
といった語感を楽しむ余裕を持ったプログラミングを心がけたいものである。
重要なのは、汎用的な名前をオブジェクトころんころん
の下でなるべく定義しないことなのだ。
付録:「ころんころんの話をしよう。」の翻訳にあたって
筆者がふだん扱うのは巨大なRails
プロジェクトであり、一つの大きなドメインに属するものである。
しかしその膨大なコード量、クラス数に比して頻出する用語は少ない。ruby
に限らずあらゆる言語の名前空間と優先順位戦争もそうであるが、この有限なる「使いやすい名前」という大切な資源を有効活用することがいま求められている。
どこで宣言するか、どんなオブジェクトであって欲しいか、何を期待するのか、プログラミングをするにあたって名付けの悩みは計り知れない。その中であって、名前空間という重要な視点について、読みやすく、多くの用例を持って解説した本稿「ころんころんの話をしよう。」
が一筋の光明になれば幸いである。
- 上記のとおりなので同じ名前で定義してもメソッドや内部の定数名が被らなければ問題は起きにくい。クラスも同様。
- であるが、結局解決順が問題になるのでだいたい
Rails
のせいと筆者は思っているようである。 -
table_name_prefixとか曲者だけどみんなどうやって対処しているんだろうか。
-
app/models/
で定義されるのでlib/
と呼び出し順が異なり、名前空間が被ると……。
-
- であるが、結局解決順が問題になるのでだいたい
注意書き及び参考文献
- この文章は「るびぃりふぁれんすまにゅある未収録事無有無」(民明書房刊)に収録されたものを原文を尊重しつつ現代語訳し再掲したものです。
- 翻訳の不備については編集リクエストにて対応します。
- 参照した web ページ
- https://docs.ruby-lang.org/ja/latest/class/Module.html#S_NEW
- https://docs.ruby-lang.org/ja/latest/doc/spec=2fdef.html#class
- https://docs.ruby-lang.org/ja/latest/doc/spec=2fdef.html#module
$ module Hoge
$ module Fuga;end
$ end
$
$ module Hoge
$ module Moga;end
$ end
$ Hoge.constants
#=> [:Fuga, :Moga]
-
- 筆者が
ころんころん
言いたいだけである。
https://docs.ruby-lang.org/ja/latest/doc/spec=2foperator.html
- 筆者が
-
-
ruby
ではモジュールが既に定義されているとき、さらに同じモジュール名でモジュール定義を書くとモジュールの定義の追加になる。同じモジュール名での定義の追加
を参照のこと。
-