Codelogy

Ruby でも型チェック

動的型付け (スクリプト) 言語では、データ型のチェックが実行時にしか行われないため、プログラムの妥当性検証・デバッグといった作業が困難になります。
例えば、Ruby でプログラムを書いていて、次のようなバグに悩まされたことのある人は多いのではないでしょうか。

  • Integer オブジェクトを参照しているべき変数が、他の型のオブジェクトを参照している。
  • そのオブジェクトが「いつ」「どこで」代入されたものなのか分からない。

この手のバグは、問題の発生 (不正な型の代入) と発覚 (エラーの発生) の位置が離れてしまうので、非常に厄介。 発生箇所を絞り込むのが難しいため、プログラムを広範囲に渡って見直すハメになります。

check_type の導入

こうしたバグへの対処を容易にするため、私はメソッドの冒頭で引数の型をチェックするようにしています。

student.rb
require 'date'
require 'check_type'

# 「学生」クラス
class Student

    attr :id
    attr :fname
    attr :lname
    attr :birthday

    # 初期化
    def initialize(id, lname, fname, birthday)
        @id       =check_type(Integer, id,       false);
        @lname    =check_type(String,  lname,    false);
        @fname    =check_type(String,  fname,    false);
        @birthday =check_type(Date,    birthday, false);
    end
end # class Stundent
check_type.rb
# 型チェック
def check_type(type, instance, nullable =false)

    if (instance.nil?)
        unless (nullable)
            raise ArgumentError.new("non-nil constraint vioration")
        end
    else
        unless (instance.kind_of?(type))
            raise(ArgumentError::new("type mismatch: #{instance.class} for #{type}"))
        end
    end

    return instance
end

メソッドに不正な型の引数を渡すと、ArgumentError が発生します。

test.rb
require 'student'

s =Student::new(200, 'Narita', 'Sho', '1981/07/05')
% student.rb:20:in `check_type': type mismatch: String for Date (ArgumentError)
from student:13:in `initialize'
from test.rb:3:in `new'

また、check_type を各メソッドの冒頭に配置することで、そのメソッドがどんな型の引数をとるのか明示することにもなるため、オススメです。

担当: 成田 (型チェックの鬼)

コメントを投稿

コメントの公開は承認制のため、投稿から掲載までに時間がかかることがあります。


About

2008年06月16日 13:00 に投稿されたエントリです。

他にも多くのエントリがあります。
メインページアーカイブページもご覧ください。