Effective Ruby をやっと読みました!
- 作者: Peter J.Jones
- 出版社/メーカー: 翔泳社
- 発売日: 2015/01/19
- メディア: Kindle版
- この商品を含むブログ (5件) を見る
薄いと思って油断したら案外重かった……!
ざっくりした感想として、Ruby がそこそこ使えるようになってきた人が読むと非常に勉強になる本、だと思いました。 読んでて「へぇ!そうなんだ!」とか「おお!やってみよう!」とか感じることが多く、面白かったです。
ただ、案外重くて、寝る前に読んでたらスヤスヤと爆睡したりもしてました。
会社で「睡眠に Effective な本なんやな」とか言われました。
素晴らしい本です。
本題
さて、実はタイトルをこちらの記事からパクリました。
いつも隣でワイワイ喋りながら働いてる同僚の記事です!
ここまでたくさん感想を書く気力がなかったので、程々に感想を書いていこうと思います。
建前としては「本を読むべき!素晴らしい!」で、本音としては「詳細は本を読んでくれ!書くのダルい!」です。
ただ、人に教えれるレベルの理解度というのは非常に高い状態だった気がするので、やはり1度自分の言葉としてアウトプットするのは非常に重要だと思います。
というわけで、ちょっと感想書きます。
折角なので先ほどの記事で触れられてない項目を選びます!
項目6 Ruby が継承階層をどのように組み立てているかを頭に入れよう
クラスメソッドはそのクラス(クラスもオブジェクト)に対する特異メソッドとして定義されているというのは有名ですが、具体的にどこに定義されてるのかは読むまで謎でした。というか、特に考えたことがなかったです。
どうやら Ruby では、特異メソッドを作る際、暗黙的に特異クラスが作成され、それが継承階層の真上に挿入され、その特異クラスのメソッドとして定義されるそうです。 全く知りませんでしたが、どうやらクラスメソッド(クラスの特異メソッド)は実はこっそり作成された特異クラスに定義され、そしてそれをそのクラスはこっそり継承しているということです。
また、インクルード時も特異クラスが暗黙的に作られ、自分の継承関係の上に挿入されます。 なんと、モジュールのインクールドも裏では継承だったのです!なんてこった!!
さて、言葉だとわかりにくいのでプログラムを書きます。
module Foo : end class Bar : end class Foobar < Bar include Foo def self.foobar_self : end def foobar : end end
雑にクラスとモジュールを定義してみました。
それでは継承関係を覗いていきます。
# まずは普通に Foobar クラスのインスタンスメソッドを見てみます >> Foobar.instance_methods(false) => [:foobar] # インスタンスメソッドが正しく返ってきました # 次に、Foobar クラスの特異クラスのインスタンスメソッドを見てみます >> Foobar.singleton_class.instance_methods(false) => [:foobar_self] # ホントに特異クラスに定義されてました # Foobar の親クラスを覗いてみます >> Foobar.superclass => Bar # 普通に親クラスが返ってきました # 次に継承階層を出力してみます >> Foobar.ancestors => [Foobar, Foo, Bar, Object, Kernel, BasicObject] # インクルードしてるモジュールが出てきた!
とまぁ、ざっくりこんな感じです。
複数モジュールがインクルードされた時の継承関係も一応見ておきましょう。
class Foobar < Bar include Moge include Foo def self.foobar_self : end def foobar : end end
このように2つインクルードすると、
>> Foobar.ancestors => [Foobar, Foo, Moge, Bar, Object, Kernel, BasicObject]
先にインクルードされてる方がより遠い祖先になりました。
単に「自分の直前に挿入する」ということをシンプルにしているということですね。
全体的に目から鱗!
項目15 クラス変数よりもクラスインスタンス変数を使うようにしよう
クラス変数はホントにそのクラスがもつスタティックな値で、完全に一意に定まります。
例えそのクラスを継承してるオブジェクトからであろうが、それは同じ変数を参照することになります。
プログラムを書いてみます。
class Bar @@bar = "bar" def self.bar=(bar) @@bar = bar end def self.bar @@bar end end class Foobar < Bar end class Hoobar < Bar end
さて、それでは確かめてみます。
# 当然どちらにも同じ値が入っています >> Foobar.bar => "bar" >> Hoobar.bar => "bar" # それでは片方書き換えてみます >> Foobar.bar = "foo" => "foo" >> Foobar.bar => "foo" >> Hoobar.bar => "foo" # こちらも変わってしまいました!
と、いった感じです。
こういう動作を意図している場合は問題ないのですが、基本的に変数スコープがデカくて嬉しいことはあまりないので、避けたいです。 それと、こういう場面では継承したクラスごとにそれぞれ別の値を持たせたいことも多い気がします。
そんな特は、クラスインスタンス変数を使いましょう。
クラスもオブジェクトなので、当然インスタンス変数を持っています。
早速使ってみましょう。
class Bar @bar = "bar" def self.bar=(bar) @bar = bar end def self.bar @bar end end class Foobar < Bar end class Hoobar < Bar end
>> Foobar.bar => nil >> Hoobar.bar => nil
およ?どちらからも見れなくなりました。 それもそのはずです、両クラスともに別のオブジェクトであるため、インスタンス変数は共有しておりません。
これで終わるのも気持ち悪いので、ちょっと書きなおしてみます。
class Bar def self.bar=(bar) @bar = bar end def self.bar @bar end end class Foobar < Bar @bar = "foobar" end class Hoobar < Bar @bar = "hoobar" end
さて、動かしてみましょう。
>> Foobar.bar => "foobar" >> Hoobar.bar => "hoobar"
意図した通りの動作になっていることが保証出来ました。
また、少し違う話ですが、今回の設定方法はクラス定義中にベタで書いてあって気持ち悪いですね。 このやり方での初期値の設定は事故の元に見えます。
ちょっとかっこよく設定できるようにしてみます。
# 設定項目を保持するクラス class Configuration attr_accessor :bar end class Bar # 継承先で呼び出してもらう設定クラス def self.configure configuration = Configuration.new yield configuration @config = configuration.bar @bar = @config.bar end def self.bar=(bar) @bar = bar end def self.bar @bar end end class Foobar < Bar # 初期化 configure do |config| config.bar = "foobar" end end class Hoobar < Bar # 初期化 configure do |config| config.bar = "hoobar" end end
こうすると、ちょっとかっこよく各クラスの初期値を渡すことが出来ます。
# ちょっとカッコ良い! configure do |config| config.foo = "foo" config.bar = "bar" end
閑話休題。
基本的にはクラスインスタンス変数を使うのが吉だと思います。
第8章 メモリ管理とパフォーマンス
これだけ章でとりあげました。
こういう話が載ってるの、凄く良いなぁと思ったのでざっくり章でとりあげました。 ガベージコレクタのチューニングや、プロファイルを取る方法などについて乗っています。
例えば「項目46 Ruby プロファイリングツールを使おう」では、
- プロファイリングツールを使ってからパフォーマンス・チューニングをしましょう
といったことが書いてあります。
また、これは Effective Ruby とは関係ありませんが、Ruby のガベージコレクタの仕組みについては以下の記事*1が図もあり、非常にわかりやすかったです。
Ruby と Python のガベージコレクタの違いについて書いてあります。
この章とは特に関係ないですが、パフォーマンス関係で思い出した記事をもう一つ紹介します。
Ruby による並列・並行プログラミングに関する記事です。
どちらも英語ですが、読んでて非常に面白かったのでオススメです!
追記
POSTD に Visualizing Garbage Collection in Ruby and Python の日本語訳が掲載されていました!
まとめ
非常に良い本だと思いますので、1度目を通してみることをオススメします!
次の本
次に読みたいなと思ってる Ruby 関係の本はこちらです。
もっと重厚です。ヤバイです。会社で買ってもらいました。
- 作者: Jay Fields,Shane Harvie,Martin Fowler,Kent Beck,長尾高弘
- 出版社/メーカー: アスキー・メディアワークス
- 発売日: 2010/02/27
- メディア: 大型本
- 購入: 9人 クリック: 321回
- この商品を含むブログ (49件) を見る
Ruby 以外の本で直近読もうと思ってる本をついでに紹介しておくと、以下の2冊です。
一億人の英文法 ――すべての日本人に贈る「話すため」の英文法(東進ブックス)
- 作者: 大西泰斗,ポール・マクベイ
- 出版社/メーカー: ナガセ
- 発売日: 2011/09/09
- メディア: 単行本(ソフトカバー)
- 購入: 12人 クリック: 68回
- この商品を含むブログ (50件) を見る
- 作者: 竹下隆史,村山公保,荒井透,苅田幸雄
- 出版社/メーカー: オーム社
- 発売日: 2012/02/25
- メディア: 単行本(ソフトカバー)
- 購入: 4人 クリック: 34回
- この商品を含むブログ (37件) を見る
そして読書会でちょこちょこ読み進めてる Haskell 並列並行本、はじパタ……いっぱいある!
キャパオーバーで死なないように、うまい感じにそれぞれを読み進めていきます。
とりあえずは英語の本とマスタリング TCP/IP 入門編を読んでみまーす!
月曜日
今日は早寝するって決めたのに……!