「7つの言語 7つの世界」1週目 Ruby

7つの言語 7つの世界」を読み始める事にしました。

これは7つのプログラミング言語(Ruby, Io, Prolog, Scala, Erlang, Clojure, Haskell)を、それぞれ1週間ずつ7週間かけて学ぶという、なんともプログラマ心をくすぐる本です。また現状で僕が触れる言語は、C言語と似た制御構文を持っているものばかりなので、この本で取り上げられている言語をつまみ食いする事で、視野が広がったりして日々書くコードがもっと良くなったら良いなぁと思って読んでみる事にしました。

ちなみに各章は5つの節、”概要”, “1日目”, “2日目”, “3日目”, “まとめ”に分かれています。1日目〜3日目までが実際に手を動かしながら読み進める部分になっていて、練習問題がついています。学習効果が期待できそうなので練習問題の解いていく作業をまとめて行きたいと思います。

第一周目はRubyです。7つの中で唯一オブジェクト指向で取っ付きやすいので肩ならしには最適ですね。あと僕が触った事がある唯一の言語でもあります。

さて、本文を通してRubyはメリー・ポピンズに例えられていて、Rubyのプログラミングを楽しむというコンセプトが説明されています。僕は知らないのですが、メリー・ポピンズというのはディズニーに出てくるキャラクタで、家事を楽しく効率的に行う乳母という設定のようです。

1日目

1日目はRubyの特徴をirbの環境で触りながら説明しています。

まずはその純粋なオブジェクト指向性です。なるほど定数もきっちりオブジェクトなんですね。Javaで言うところのプリミティブ型みたいな、中途半端な要素がなくて綺麗ですね。

$ irb
>> 4.class
=> Fixnum
>> true.class
=> TrueClass

そして後置ifやunlessなど、短く書ける条件分がイイネという話に続いて、動的片付けとダックタイピングについての説明で1日目は終わり。簡単なので練習問題もスキップします。

2日目

2日目は配列 => ハッシュ => ブロック => クラス定義と重要な機能を列挙しています。そして最後にMixinの説明があるのですが、恥ずかしながらこの機能を知りませんでした。これはモジュールという単位でメソッドの実装のみを切り出しておいて、必要に応じてクラスに組み込める仕組みのようです。以下のコードが例として上げられていました。ToFileモジュールに実装されているto_fというメソッドを、Personクラスにincludeして組み込んでいます。

module ToFile
  def filename
    "object_#{self.object_id}.txt"
  end
  
  def to_f
    File.open(filename, 'w') {|f| f.write(to_s)}
  end
end

class Person
  include ToFile
  attr_accessor :name

  def initialize(name)
    @name = name
  end

  def to_s
    name
  end
end

Person.new('taichino').to_f

淡々と書きましたが、最初に説明を読んだときは、あぁポリモーフィズムってこれで実装すれば良いんや!と感動しました。C++みたいな多重継承じゃ自由度高すぎるし、Javaみたいなインターフェースじゃ手間増えてるだけやんって言うのが解決されてますね。多重継承できる環境の時は、1つのスーパークラスと複数のモジュールという風に制約をもうけたら同じ事ができるので、これは良かったです。いきなりであれなんですけど、これ知っただけでもうこの本ペイした感じです。

2日目も練習問題は特につまるところはありませんでした。

3日目

3日目はRubyでのメタプログラミングをちょっとだけ触ってみようと言う節です。まず最初にオープンクラスについて説明されています。機能名は知らなかったのですが、普段Pythonを書いていてRubyがうらやましくなる1番の機能がこれです。要はクラスの機能を上書きできるという話で、標準クラスライブラリ中のStringだろうがNilClassだろうがおかまいなしに振舞いを変更できます。Objective-Cのカテゴリも似たような事ができますね。

# 文字列クラスにメソッドを追加
class String
  def blank?
    self.size == 0
  end
end

何年か前に、高林哲さんの書かれたRomkanのコードを読んでいる時に、この機能を上手く使うとドメインが絞れるコードはすごくスッキリするんや!と感銘を受けたのを思い出しました。

オープンクラスに続いて、上述のモジュールを使った例の説明などで3日目は終わりでした。

3日目の練習問題は少し手こずったので張っておきます。

class CsvRow
  attr_accessor :columns, :headers  
  
  def initialize(row, headers)
    @columns = row.chomp.split(',')
    @headers = headers
  end

  def method_missing(name, *args)
    idx = @headers.index(name.to_s)
    return nil if not idx
    return @columns[idx]
  end
end

module ActsAsCsv
  def self.included(klass)
    klass.extend ClassMethods
  end

  module ClassMethods
    def acts_as_csv
      include InstanceMethods
    end
  end

  module InstanceMethods
    attr_accessor :headers, :contents
    
    def read
      @contents = []
      filename = self.class.to_s.downcase + '.txt'
      file = File.new(filename)
      headers = file.gets.split(',').map{|item| item.strip }
      file.each {|row|
        @contents < < CsvRow.new(row, headers)
      }
    end

    def each(&block)
      @contents.each(&block)
    end
    
    def initialize
      read
    end
  end
end

class RubyCsv
  include ActsAsCsv
  acts_as_csv
end

m = RubyCsv.new
m.each {|row|
  puts row.one
}

まとめ

最後に長所と短所が書かれていて、1行で書くと"柔軟で書きやすいけど遅いんだよね"とのことです。そんなん知ってるw
あとWebアプリとも相性が良いとのこと。それも知ってるw あとperlで言うところのcpanモジュールであるgemが充実してるので本来書くべきコードに集中できるぜ!とのこと。確かにgemには色々面白いモジュールがある印象なので、ざっと眺めてみるのも良いかもしれません。

あとOOPの大きな欠点は平行性だと書かれていて、今のところ「?」なのでこの本読み終わるまでに理解できたら良いなぁということろです。改めてRuby触ってるとやっぱり綺麗なので、なんか1個くらいRubyでコード書きたくなってきました。

一応、練習問題で書いたコードはgithubに上げています。

次はIoです。Rubyと違って何も知らないので、次からが本番ですね。

Leave a Reply

Your email address will not be published. Required fields are marked *